import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises'
import { join } from 'node:path'

const root = process.cwd()
const contentRoot = join(root, 'data', 'content')
const outRoot = join(root, 'content_population_exports')
const assetValidationPath = join(outRoot, 'asset_manifest_validation.json')
const clinicalBlankDecisionPath = join(contentRoot, 'compliance', 'clinical-blank-decisions.json')

const productColumns = [
  'Handle',
  'Metafield: filter.dietary_tag [list.metaobject_reference]',
  'Metafield: filter.health_goals [list.metaobject_reference]',
  'Metafield: pdp.key_ingredients [metaobject_reference]',
  'Metafield: pdp.benefits [metaobject_reference]',
  'Metafield: pdp.clinically_shown_to [metaobject_reference]',
  'Metafield: breadcrumb.primary_collection [collection_reference]',
  'Metafield: filter.strength [single_line_text_field]',
  'Metafield: pdp.who_its_for [single_line_text_field]',
  'Metafield: pdp.product_benefits [list.single_line_text_field]',
  'Metafield: pdp.key_features [multi_line_text_field]',
  'Metafield: pdp.results [file_reference]',
  'Metafield: pdp.results_mobile [file_reference]',
  'Metafield: pdp.how_we_compare [file_reference]',
  'Metafield: faq.heading_one [single_line_text_field]',
  'Metafield: faq.heading_two [single_line_text_field]',
  'Metafield: faq.heading_three [single_line_text_field]',
  'Metafield: faq.answer_one [multi_line_text_field]',
  'Metafield: faq.answer_two [multi_line_text_field]',
  'Metafield: faq.answer_three [multi_line_text_field]',
  'Variant SKU',
  'Variant Metafield: pdp.tag [single_line_text_field]',
  'Variant Metafield: pdp.colour [color]',
  'Variant Metafield: pdp.price_per [single_line_text_field]',
  'Variant Metafield: pdp.strapline [single_line_text_field]'
]

const metaColumns = ['Handle', 'Display Name', 'Status', 'Definition: Handle', 'Definition: Name', 'Field', 'Value']
const metaDefinitionNames = {
  dietary_tag: 'Dietary Tag',
  health_goals: 'Health Goals',
  key_ingredients: 'Key Ingredients',
  benefits: 'Full Description - Benefits',
  clinically_shown_to: 'Clinically Shown To...',
  promo_card: 'Promo Card (Collections)'
}

function csvEscape(value) {
  if (Array.isArray(value)) value = value.join(', ')
  if (value === undefined || value === null) value = ''
  value = String(value)
  return /[",\n\r]/.test(value) ? `"${value.replace(/"/g, '""')}"` : value
}
function toCsv(rows) {
  return rows.map(row => row.map(csvEscape).join(',')).join('\n') + '\n'
}
async function readJson(path) { return JSON.parse(await readFile(path, 'utf8')) }
async function readJsonFallback(path, fallback) {
  try { return await readJson(path) } catch (_) { return fallback }
}
function asList(value) {
  if (Array.isArray(value)) return value.map(v => String(v).trim()).filter(Boolean)
  if (value === undefined || value === null || value === '') return []
  if (typeof value === 'string') return value.split(',').map(v => v.trim()).filter(Boolean)
  return [String(value)]
}
function countBy(rows, key) {
  return rows.reduce((acc, row) => {
    const value = row[key] || 'unknown'
    acc[value] = (acc[value] || 0) + 1
    return acc
  }, {})
}
function uniqueSkus(rows) { return [...new Set(rows.map(row => row.sku).filter(Boolean))].sort() }
function isApprovedBlankClinicalDecision(decision) {
  return decision?.decision === 'approved_blank' &&
    Boolean(decision.approvedBy) &&
    Boolean(decision.approvedAt) &&
    Boolean(decision.rationale) &&
    decision.constraintsAcknowledged === true
}

await mkdir(outRoot, { recursive: true })
const generatedAt = new Date().toISOString()
const assetValidation = await readJsonFallback(assetValidationPath, null)
const clinicalBlankDecisions = await readJsonFallback(clinicalBlankDecisionPath, { decisions: [] })
const clinicalBlankDecisionBySku = new Map((clinicalBlankDecisions.decisions || []).map(row => [row.sku, row]))
const productFiles = (await readdir(join(contentRoot, 'products'))).filter(f => f.endsWith('.json'))
const products = []
for (const file of productFiles) products.push(await readJson(join(contentRoot, 'products', file)))
products.sort((a, b) => a.sku.localeCompare(b.sku))

const productRows = [productColumns]
const blockers = []
for (const product of products) {
  const m = product.metafields || {}
  if (!m.pdpClinicallyShownTo && !isApprovedBlankClinicalDecision(clinicalBlankDecisionBySku.get(product.sku))) {
    blockers.push({ sku: product.sku, type: 'compliance', blocker: 'Missing pdp.clinically_shown_to or approved blank compliance decision' })
  }
  for (const field of ['pdpResults', 'pdpResultsMobile', 'pdpHowWeCompare']) {
    if (!m[field]) blockers.push({ sku: product.sku, type: 'asset', blocker: `Missing ${field}` })
  }
  if (!product.approval || product.approval.content !== 'approved') {
    blockers.push({ sku: product.sku, type: 'approval', blocker: 'Content not approved' })
  }
  ;(product.variants || [{ sku: product.sku }]).forEach((variant, index) => {
    const first = index === 0
    productRows.push([
      product.handle,
      first ? asList(m.filterDietaryTag).join(', ') : '',
      first ? asList(m.filterHealthGoals).join(', ') : '',
      first ? m.pdpKeyIngredients : '',
      first ? m.pdpBenefits : '',
      first ? m.pdpClinicallyShownTo : '',
      first ? m.breadcrumbPrimaryCollection : '',
      first ? m.filterStrength : '',
      first ? m.pdpWhoItsFor : '',
      first ? JSON.stringify(asList(m.pdpProductBenefits)) : '',
      first ? m.pdpKeyFeatures : '',
      first ? m.pdpResults : '',
      first ? m.pdpResultsMobile : '',
      first ? m.pdpHowWeCompare : '',
      first ? m.faqHeadingOne : '',
      first ? m.faqHeadingTwo : '',
      first ? m.faqHeadingThree : '',
      first ? m.faqAnswerOne : '',
      first ? m.faqAnswerTwo : '',
      first ? m.faqAnswerThree : '',
      variant.sku,
      variant.pdpTag,
      variant.pdpColour,
      variant.pdpPricePer,
      variant.pdpStrapline
    ])
  })
}
if (assetValidation?.missingReferences?.length) {
  for (const item of assetValidation.missingReferences) {
    blockers.push({ sku: item.Owner || item.owner || '', type: 'asset_reference', blocker: `${item.Field || item.field} filename missing` })
  }
}
if (assetValidation?.required?.length) {
  for (const item of assetValidation.required.filter((row) => (row.Exists || row.exists) === 'no' || row.exists === false)) {
    blockers.push({ sku: item.Owner || item.owner || '', type: 'asset_upload', blocker: `${item.Field || item.field} file not found/uploaded: ${item.Filename || item.filename}` })
  }
}
await writeFile(join(outRoot, 'products_content_matrixify.csv'), toCsv(productRows), 'utf8')

const meta = await readJson(join(contentRoot, 'metaobjects.json'))
const metaRows = [metaColumns]
const metaobjectCounts = {}
for (const [definition, rows] of Object.entries(meta.definitions || {})) {
  metaobjectCounts[definition] = rows.length
  for (const row of rows) {
    const handle = row.handle || row.name_internal || row.name
    const displayName = row.name || row.heading || row.name_internal || handle
    const status = ['active', 'approved', 'ready'].includes(String(row.status || '').toLowerCase()) ? 'Active' : 'Draft'
    const definitionName = metaDefinitionNames[definition] || definition
    for (const [field, value] of Object.entries(row)) {
      if (field === 'handle' || field === 'status' || field === 'source') continue
      metaRows.push([handle, displayName, status, definition, definitionName, field, value])
    }
  }
}
await writeFile(join(outRoot, 'metaobjects_matrixify.csv'), toCsv(metaRows), 'utf8')

const collections = await readJson(join(contentRoot, 'smart-collections.json'))
const collectionRows = [['Handle', 'Metafield: custom.promo_card [metaobject_reference]'], ...(collections.collections || []).map(c => [c.handle, c.promoCard])]
await writeFile(join(outRoot, 'smart_collections_matrixify.csv'), toCsv(collectionRows), 'utf8')
await writeFile(join(outRoot, 'export_blockers.csv'), toCsv([['SKU', 'Type', 'Blocker'], ...blockers.map(b => [b.sku, b.type, b.blocker])]), 'utf8')

const blockersByType = countBy(blockers, 'type')
const blockedSkus = uniqueSkus(blockers)
const manifest = {
  generatedAt,
  readyForLewis: blockers.length === 0,
  source: 'jv-dashboard/data/content',
  outputs: {
    products: 'products_content_matrixify.csv',
    metaobjects: 'metaobjects_matrixify.csv',
    smartCollections: 'smart_collections_matrixify.csv',
    blockers: 'export_blockers.csv',
    handoffManifest: 'handoff_manifest.json',
    handoffSummary: 'handoff_summary.md'
  },
  counts: {
    productRecords: products.length,
    variantRows: productRows.length - 1,
    metaobjectRows: metaRows.length - 1,
    smartCollectionRows: collectionRows.length - 1,
    blockers: blockers.length,
    blockedSkus: blockedSkus.length
  },
  blockerSummary: blockersByType,
  clinicalBlankDecisions: {
    decisionFile: 'data/content/compliance/clinical-blank-decisions.json',
    validBlankApprovals: [...clinicalBlankDecisionBySku.values()].filter(isApprovedBlankClinicalDecision).length,
    totalDecisionRows: clinicalBlankDecisionBySku.size
  },
  metaobjectCounts,
  blockedSkus,
  nextActions: [
    blockersByType.compliance ? 'Add source-backed clinical claims and map pdp.clinically_shown_to metaobjects, or record approved_blank compliance decisions for SKUs that should intentionally omit the module.' : null,
    blockersByType.asset ? 'Assign/produce PDP result, mobile result, and comparison filenames, then upload to Shopify Files before import.' : null,
    blockersByType.approval ? 'Complete dashboard human review and mark content approved before handoff.' : null,
    'Run migration folder Matrixify emitters and staging import spot-checks with Lewis/Euan.'
  ].filter(Boolean)
}
await writeFile(join(outRoot, 'handoff_manifest.json'), JSON.stringify(manifest, null, 2) + '\n', 'utf8')

const summary = [
  '# JV Shopify Matrixify handoff summary',
  '',
  `Generated: ${generatedAt}`,
  '',
  `Ready for Lewis/Euan: **${manifest.readyForLewis ? 'YES' : 'NO'}**`,
  '',
  '## Output files',
  ...Object.values(manifest.outputs).map(file => `- ${file}`),
  '',
  '## Counts',
  `- Product records: ${manifest.counts.productRecords}`,
  `- Product/variant CSV rows: ${manifest.counts.variantRows}`,
  `- Metaobject rows: ${manifest.counts.metaobjectRows}`,
  `- Smart collection rows: ${manifest.counts.smartCollectionRows}`,
  `- Blockers: ${manifest.counts.blockers}`,
  `- Blocked SKUs: ${manifest.counts.blockedSkus}`,
  '',
  '## Blockers by type',
  ...Object.entries(blockersByType).map(([type, count]) => `- ${type}: ${count}`),
  ...(Object.keys(blockersByType).length ? [] : ['- None']),
  '',
  '## Next actions',
  ...manifest.nextActions.map(action => `- ${action}`),
  ''
].join('\n')
await writeFile(join(outRoot, 'handoff_summary.md'), summary, 'utf8')

console.log(`Wrote ${outRoot}`)
console.log(`${products.length} product records, ${blockers.length} blockers`)
console.log(`Handoff ready: ${manifest.readyForLewis ? 'yes' : 'no'}`)
