#!/usr/bin/env bun
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'
import { join } from 'path'

const root = process.cwd()
const outRoot = join(root, 'content_population_exports')
const dataforseoRoot = join(root, 'data', 'sources', 'dataforseo')
const candidatePath = join(dataforseoRoot, 'asin-candidates.csv')
const asinMapPath = join(dataforseoRoot, 'asin-map.csv')
mkdirSync(outRoot, { recursive: true })
mkdirSync(dataforseoRoot, { recursive: true })

function csv(rows: any[], headers: string[]) {
  const esc = (value: any) => {
    if (value === undefined || value === null) value = ''
    if (Array.isArray(value)) value = value.join(' | ')
    value = String(value)
    return /[",\n\r]/.test(value) ? `"${value.replace(/"/g, '""')}"` : value
  }
  return [headers.join(','), ...rows.map(row => headers.map(header => esc(row[header])).join(','))].join('\n') + '\n'
}

function parseCsv(text: string) {
  const rows: string[][] = []
  let row: string[] = []
  let cell = ''
  let quoted = false
  for (let index = 0; index < text.length; index += 1) {
    const char = text[index]
    const next = text[index + 1]
    if (quoted) {
      if (char === '"' && next === '"') { cell += '"'; index += 1 }
      else if (char === '"') quoted = false
      else cell += char
    } else if (char === '"') quoted = true
    else if (char === ',') { row.push(cell); cell = '' }
    else if (char === '\n') { row.push(cell); rows.push(row); row = []; cell = '' }
    else if (char !== '\r') cell += char
  }
  if (cell || row.length) { row.push(cell); rows.push(row) }
  const headers = rows.shift()?.map(header => header.trim()) || []
  return rows.filter(values => values.some(value => value.trim())).map(values => Object.fromEntries(headers.map((header, index) => [header, (values[index] || '').trim()])))
}

if (!existsSync(candidatePath)) {
  writeFileSync(candidatePath, csv([], ['SKU', 'Product', 'CandidateASIN', 'CandidateProductUrl', 'EvidenceSource', 'EvidenceUrl', 'EvidenceTitle', 'MatchStatus', 'Confidence', 'Notes']), 'utf8')
}

const generatedAt = new Date().toISOString()
const asinRows = existsSync(asinMapPath) ? parseCsv(readFileSync(asinMapPath, 'utf8')) : []
const candidates = parseCsv(readFileSync(candidatePath, 'utf8'))
const targetSkus = new Set(asinRows.map((row: any) => row.SKU))
const candidateRows = candidates.map((row: any) => {
  const asinLooksValid = /^[A-Z0-9]{10}$/.test(row.CandidateASIN || '')
  const status = row.MatchStatus || 'candidate_needs_amazon_confirmation'
  const confidence = row.Confidence || 'unknown'
  const targetKnown = targetSkus.has(row.SKU)
  const canPromote = asinLooksValid && targetKnown && status === 'amazon_confirmed_exact_match' && confidence === 'high'
  const blockers = []
  if (!targetKnown) blockers.push('SKU not in Stage 1 ASIN map')
  if (!asinLooksValid) blockers.push('candidate ASIN is not 10 uppercase alphanumeric characters')
  if (status !== 'amazon_confirmed_exact_match') blockers.push('not confirmed on Amazon product page')
  if (confidence !== 'high') blockers.push(`confidence is ${confidence}`)
  return {
    ...row,
    CandidateASINValid: asinLooksValid ? 'yes' : 'no',
    TargetKnown: targetKnown ? 'yes' : 'no',
    PromoteToAsinMap: canPromote ? 'yes' : 'no',
    Blockers: blockers.join(' | ')
  }
})

const manifest = {
  generatedAt,
  ready: candidateRows.some((row: any) => row.PromoteToAsinMap === 'yes'),
  counts: {
    candidates: candidateRows.length,
    stageOneTargets: targetSkus.size,
    validAsinShape: candidateRows.filter((row: any) => row.CandidateASINValid === 'yes').length,
    highConfidenceConfirmed: candidateRows.filter((row: any) => row.PromoteToAsinMap === 'yes').length,
    needsAmazonConfirmation: candidateRows.filter((row: any) => row.MatchStatus !== 'amazon_confirmed_exact_match').length
  },
  files: {
    candidatesCsv: 'data/sources/dataforseo/asin-candidates.csv',
    reportCsv: 'content_population_exports/dataforseo_asin_candidate_report.csv',
    reportJson: 'content_population_exports/dataforseo_asin_candidate_report.json',
    reportMd: 'content_population_exports/dataforseo_asin_candidate_report.md'
  },
  guardrails: [
    'Candidates do not unlock DataForSEO spend.',
    'Only copy a candidate to asin-map.csv after opening the Amazon product page and confirming exact Just Vitamins product/pack match.',
    'Set MatchStatus=amazon_confirmed_exact_match and Confidence=high only after Amazon-page confirmation.'
  ],
  candidates: candidateRows
}

writeFileSync(join(outRoot, 'dataforseo_asin_candidate_report.json'), JSON.stringify(manifest, null, 2) + '\n', 'utf8')
writeFileSync(join(outRoot, 'dataforseo_asin_candidate_report.csv'), csv(candidateRows, ['SKU', 'Product', 'CandidateASIN', 'CandidateProductUrl', 'EvidenceSource', 'EvidenceUrl', 'EvidenceTitle', 'MatchStatus', 'Confidence', 'CandidateASINValid', 'TargetKnown', 'PromoteToAsinMap', 'Blockers', 'Notes']), 'utf8')
writeFileSync(join(outRoot, 'dataforseo_asin_candidate_report.md'), [
  '# DataForSEO ASIN candidate report',
  '',
  `Generated: ${generatedAt}`,
  '',
  'This is a no-spend candidate log. It helps narrow the manual lookup work, but it intentionally does not update `asin-map.csv` or create paid task rows.',
  '',
  `- Candidates logged: ${manifest.counts.candidates}`,
  `- Valid ASIN-shaped candidates: ${manifest.counts.validAsinShape}`,
  `- High-confidence Amazon-confirmed candidates: ${manifest.counts.highConfidenceConfirmed}`,
  `- Still needing Amazon confirmation: ${manifest.counts.needsAmazonConfirmation}`,
  '',
  '## Guardrails',
  ...manifest.guardrails.map(item => `- ${item}`),
  '',
  '## Candidates',
  ...candidateRows.map((row: any) => `- [${row.PromoteToAsinMap === 'yes' ? 'promotable' : 'verify'}] ${row.SKU} — ${row.CandidateASIN || 'no ASIN'} — ${row.Confidence}; blockers: ${row.Blockers || 'none'}`),
  ''
].join('\n'), 'utf8')

console.log(`DataForSEO ASIN candidates ready: ${manifest.ready}`)
console.log(`Candidates: ${manifest.counts.candidates}`)
console.log(`High-confidence confirmed: ${manifest.counts.highConfidenceConfirmed}`)
console.log(`Needs Amazon confirmation: ${manifest.counts.needsAmazonConfirmation}`)
