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

const root = process.cwd()
const outRoot = join(root, 'content_population_exports')
const amazonRoot = join(root, 'data', 'sources', 'amazon')
mkdirSync(outRoot, { recursive: true })
mkdirSync(amazonRoot, { recursive: true })

function readJson(path: string, fallback: any = null) {
  if (!existsSync(path)) return fallback
  return JSON.parse(readFileSync(path, 'utf8').replace(/^\uFEFF/, ''))
}

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 asText(value: any) {
  return String(value ?? '').trim()
}

function matches(expected: any, actual: any) {
  return asText(expected).toLowerCase() === asText(actual).toLowerCase()
}

function sourcePathFor(row: any) {
  return join(root, normalize(row.SourceDropPath || ''))
}

function reviewText(row: any) {
  return asText(row.review_body || row.comment || row.body || row.text || row.review_title)
}

function validateReview(row: any, index: number) {
  const issues: string[] = []
  const text = reviewText(row)
  const rating = Number(row.rating)
  if (text.length < 5) issues.push(`review ${index}: missing text`)
  if (!Number.isFinite(rating) || rating < 1 || rating > 5) issues.push(`review ${index}: rating must be 1-5`)
  if (!asText(row.url || row.review_url || row.source_url)) issues.push(`review ${index}: missing review/source URL`)
  return issues
}

const generatedAt = new Date().toISOString()
const queueManifest = readJson(join(outRoot, 'manual_amazon_review_capture.json'), {})
const queue = Array.isArray(queueManifest.queue) ? queueManifest.queue : []

const rows = queue.map((queueRow: any) => {
  const filePath = sourcePathFor(queueRow)
  const issues: string[] = []
  let reviewsCaptured = 0
  let status = 'missing'
  if (!existsSync(filePath)) {
    issues.push(`missing source drop ${queueRow.SourceDropPath}`)
  } else {
    try {
      const data = readJson(filePath, {})
      const reviews = Array.isArray(data.reviews) ? data.reviews : []
      reviewsCaptured = reviews.length
      if (data.source !== 'amazon') issues.push('source must be amazon')
      if (!matches(queueRow.SKU, data.sku)) issues.push(`sku mismatch: expected ${queueRow.SKU}`)
      if (!matches(queueRow.ASIN, data.asin)) issues.push(`asin mismatch: expected ${queueRow.ASIN}`)
      if (!asText(data.brand)) issues.push('missing brand')
      if (!matches(queueRow.ProductUrl, data.productUrl)) issues.push('productUrl mismatch')
      if (!asText(data.capturedAt)) issues.push('missing capturedAt')
      if (reviews.length === 0) issues.push('reviews must be non-empty')
      for (const [index, review] of reviews.entries()) {
        issues.push(...validateReview(review, index))
      }
    } catch (error: any) {
      issues.push(`invalid JSON: ${error.message}`)
    }
  }
  status = issues.length ? (existsSync(filePath) ? 'invalid' : 'missing') : 'valid'
  return {
    SKU: queueRow.SKU,
    Product: queueRow.Product,
    ASIN: queueRow.ASIN,
    SourceDropPath: queueRow.SourceDropPath,
    Status: status,
    ReviewsCaptured: reviewsCaptured,
    Issues: issues,
    FilePresent: existsSync(filePath) ? 'yes' : 'no'
  }
})

const filesPresent = rows.filter(row => row.FilePresent === 'yes').length
const filesValid = rows.filter(row => row.Status === 'valid').length
const reviewsCaptured = rows.reduce((sum, row) => sum + row.ReviewsCaptured, 0)
const blockers = rows.filter(row => row.Status !== 'valid')
const ready = queue.length > 0 && filesValid === queue.length

const manifest = {
  generatedAt,
  ready,
  recommendation: ready
    ? 'Manual Amazon source drops are present and valid for the queued Stage 1 ASINs. Run bun run validate:sources next.'
    : 'Manual Amazon source drops are not complete. Do not treat the fallback queue as captured source evidence until every listed JSON file exists and validates.',
  queueFile: 'content_population_exports/manual_amazon_review_capture.json',
  sourceDropDir: 'data/sources/amazon',
  counts: {
    targets: queue.length,
    filesPresent,
    filesValid,
    reviewsCaptured,
    blockers: blockers.length
  },
  rows,
  blockers
}

writeFileSync(join(outRoot, 'manual_amazon_review_capture_validation.json'), JSON.stringify(manifest, null, 2) + '\n', 'utf8')
writeFileSync(join(outRoot, 'manual_amazon_review_capture_validation.csv'), csv(rows.map(row => ({
  ...row,
  Issues: row.Issues
})), ['SKU', 'Product', 'ASIN', 'SourceDropPath', 'Status', 'FilePresent', 'ReviewsCaptured', 'Issues']), 'utf8')
writeFileSync(join(outRoot, 'manual_amazon_review_capture_validation.md'), [
  '# Manual Amazon review capture validation',
  '',
  `Generated: ${generatedAt}`,
  '',
  `Ready: ${ready ? 'YES' : 'NO'}`,
  '',
  manifest.recommendation,
  '',
  `Targets: ${manifest.counts.targets}`,
  `Files present: ${manifest.counts.filesPresent}/${manifest.counts.targets}`,
  `Files valid: ${manifest.counts.filesValid}/${manifest.counts.targets}`,
  `Reviews captured: ${manifest.counts.reviewsCaptured}`,
  `Blockers: ${manifest.counts.blockers}`,
  '',
  '## Target status',
  ...rows.map(row => [
    `### ${row.SKU} — ${row.Status}`,
    `- ASIN: ${row.ASIN}`,
    `- File: \`${row.SourceDropPath}\``,
    `- Reviews captured: ${row.ReviewsCaptured}`,
    `- Issues: ${row.Issues.length ? row.Issues.join('; ') : 'none'}`,
    ''
  ].join('\n')),
  '## Rule',
  'This gate validates completed manual capture files only. It never creates fake Amazon reviews and it does not call Amazon, DataForSEO, Apify, or Shopify.',
  ''
].join('\n'), 'utf8')

console.log(`Manual Amazon capture validation ready: ${ready}`)
console.log(`Files valid: ${manifest.counts.filesValid}/${manifest.counts.targets}`)
console.log(`Reviews captured: ${manifest.counts.reviewsCaptured}`)
