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

const root = process.cwd()
const rawRoot = join(root, 'data', 'sources', 'apify', 'raw')
const intelRoot = join(root, 'data', 'intelligence')
const profileRoot = join(root, 'data', 'research-profiles')
const outRoot = join(root, 'content_population_exports')
const generatedAt = new Date().toISOString()
const top3 = ['JV-TURMERIC500', 'JV-DEFF1000', 'JV-VISISOFT']
const rawFiles = [
  join(rawRoot, 'top3-comprehensive-source-scrape-latest.json'),
  join(rawRoot, 'top3-social-source-scrape-latest.json')
]
const specialistFiles = existsSync(rawRoot)
  ? readdirSync(rawRoot)
    .filter(file => /^top3-specialist-.*-latest\.json$/.test(file))
    .map(file => join(rawRoot, file))
  : []

function readJson(path: string, fallback: any = null) {
  if (!existsSync(path)) return fallback
  return JSON.parse(readFileSync(path, 'utf8').replace(/^\uFEFF/, ''))
}
function writeJson(path: string, data: any) {
  mkdirSync(dirname(path), { recursive: true })
  writeFileSync(path, JSON.stringify(data, null, 2) + '\n', 'utf8')
}
function compactItem(item: any) {
  return {
    sku: item.sku,
    sourceType: item.sourceType,
    label: item.label,
    competitor: item.competitor || null,
    requestedUrl: item.requestedUrl,
    loadedUrl: item.loadedUrl,
    statusCode: item.statusCode,
    title: item.title,
    metaDescription: item.metaDescription,
    h1: item.h1,
    headings: item.headings || [],
    prices: item.prices || [],
    reviewLike: item.reviewLike || [],
    links: item.links || [],
    text: item.text || '',
    textChars: item.textChars || String(item.text || '').length,
    htmlChars: item.htmlChars || 0,
    capturedAt: item.capturedAt
  }
}
function itemMatchesSku(item: any, sku: string) {
  if (item.sku === sku || item.sku === 'ALL_TOP3') return true
  if (item.sku) return false
  const text = JSON.stringify(item).toLowerCase()
  if (sku === 'JV-TURMERIC500') return /turmeric|curcumin|bioperine|black pepper/.test(text)
  if (sku === 'JV-DEFF1000') return /vitamin d|1000iu|1000 iu|effervescent|fizz|deficien/.test(text)
  if (sku === 'JV-VISISOFT') return /visisoft|lutein|zeaxanthin|bilberry|eye health|vision/.test(text)
  return false
}

const runs = rawFiles.map(path => ({ path, data: readJson(path) })).filter(row => row.data)
const specialistRuns = specialistFiles.map(path => ({ path, data: readJson(path) })).filter(row => row.data)
const specialistJobs = Array.from(new Set([
  'trustpilot',
  'reddit',
  'amazon-reviews',
  ...specialistRuns.map(run => run.data?.job).filter(Boolean)
])).sort()
const manifestRows: any[] = []
for (const sku of top3) {
  const items = runs.flatMap(run => (run.data.items || [])
    .filter((item: any) => item.sku === sku || item.sku === 'ALL_TOP3')
    .map((item: any) => ({ ...compactItem(item), rawFile: run.path, runId: run.data.run?.id })))
  const requested = runs.flatMap(run => (run.data.requestedTargets || [])
    .filter((target: any) => target.sku === sku || target.sku === 'ALL_TOP3')
    .map((target: any) => ({ ...target, rawFile: run.path, runId: run.data.run?.id })))
  const capturedLabels = new Set(items.map((item: any) => item.label))
  const missing = requested.filter((target: any) => !capturedLabels.has(target.label))
  const byType = Object.fromEntries(['jv_public_pdp', 'competitor_pdp', 'amazon_search', 'trustpilot_brand', 'reddit_category'].map(type => [
    type,
    {
      requested: requested.filter((row: any) => row.sourceType === type).length,
      captured: items.filter((row: any) => row.sourceType === type).length
    }
  ]))
  const specialistItems = specialistRuns.flatMap(run => (run.data.items || [])
    .filter((item: any) => run.data.job === 'trustpilot' || itemMatchesSku(item, sku))
    .map((item: any) => ({
      sourceType: `specialist_${run.data.job}`,
      job: run.data.job,
      actor: run.data.actor,
      rawFile: run.path,
      runId: run.data.run?.id,
      item
    })))
  const exactProductEvidenceCount = specialistItems.filter((row: any) =>
    row.item?.sku === sku &&
    row.item?.matchContext !== 'closest_effervescent_competitor' &&
    row.item?.matchContext !== 'exact_asin_absence_search' &&
    row.item?.matchContext !== 'competitor_serp_fallback' &&
    row.item?.matchContext !== 'competitor_retailer_pdp_fallback' &&
    !['specialist_healthspan-serp', 'specialist_healthspan-browser', 'specialist_healthspan-content-crawler', 'specialist_healthspan-retailer'].includes(row.sourceType)
  ).length
  const competitorContextEvidenceCount = specialistItems.filter((row: any) =>
    row.item?.matchContext === 'closest_effervescent_competitor' ||
    row.item?.matchContext === 'exact_asin_absence_search' ||
    row.item?.matchContext === 'competitor_serp_fallback' ||
    row.item?.matchContext === 'competitor_retailer_pdp_fallback' ||
    row.sourceType === 'specialist_healthspan-serp' ||
    row.sourceType === 'specialist_healthspan-browser' ||
    row.sourceType === 'specialist_healthspan-content-crawler' ||
    row.sourceType === 'specialist_healthspan-retailer'
  ).length
  const specialistCoverage = Object.fromEntries(specialistJobs.map(job => [
    job,
    {
      run: specialistRuns.some(run => run.data.job === job),
      captured: specialistItems.filter((row: any) => row.job === job).length,
      status: specialistRuns.find(run => run.data.job === job)?.data?.run?.status || 'not_run'
    }
  ]))
  const captureProfile = {
    sku,
    generatedAt,
    generatedBy: 'ingest-apify-top3-source-captures.ts',
    purpose: 'Raw Apify source captures for comprehensive PDP research profile.',
    sourceFiles: runs.map(run => ({
      path: run.path,
      runId: run.data.run?.id,
      status: run.data.run?.status,
      requestCap: run.data.requestCap,
      itemCount: run.data.itemCount,
      usageTotalUsd: run.data.run?.usageTotalUsd
    })),
    coverage: byType,
    specialistCoverage,
    evidenceContext: {
      exactProductEvidenceCount,
      competitorContextEvidenceCount,
      note: 'Exact product evidence is tied to the SKU/confirmed listing. Competitor context is useful for market/PDP learning but must not override JV product truth.'
    },
    capturedCount: items.length,
    specialistCapturedCount: specialistItems.length,
    requestedCount: requested.length,
    missingCount: missing.length,
    missing,
    items,
    specialistItems
  }
  writeJson(join(intelRoot, sku, 'apify-source-captures.json'), captureProfile)
  const profilePath = join(profileRoot, `${sku}.json`)
  const profile = readJson(profilePath)
  if (profile) {
    profile.rawSourceCaptureProfile = {
      generatedAt,
      source: `${sku}/apify-source-captures.json`,
      coverage: byType,
      capturedCount: items.length,
      specialistCapturedCount: specialistItems.length,
      missingCount: missing.length,
      specialistCoverage,
      evidenceContext: {
        exactProductEvidenceCount,
        competitorContextEvidenceCount,
        note: 'Exact product evidence is tied to the SKU/confirmed listing. Competitor context is useful for market/PDP learning but must not override JV product truth.'
      },
      missing: missing.map((row: any) => ({ sourceType: row.sourceType, label: row.label, url: row.url }))
    }
    profile.sourceCoverage = {
      ...(profile.sourceCoverage || {}),
      apifyRawCaptures: items.length,
      apifySpecialistRawCaptures: specialistItems.length,
      apifyMissingTargets: missing.length
    }
    writeJson(profilePath, profile)
    writeJson(join(intelRoot, sku, 'research-profile.json'), profile)
  }
  manifestRows.push({ sku, captured: items.length, specialistCaptured: specialistItems.length, requested: requested.length, missing: missing.length, coverage: byType, specialistCoverage, evidenceContext: { exactProductEvidenceCount, competitorContextEvidenceCount } })
}

const manifest = {
  generatedAt,
  ready: manifestRows.every(row => row.captured > 0),
  note: 'Apify capture ingest is raw-source coverage, not content approval. Reddit/Trustpilot may remain missing when source pages block crawler access.',
  rawFiles: runs.map(run => run.path),
  specialistFiles: specialistRuns.map(run => run.path),
  products: manifestRows
}
writeJson(join(outRoot, 'top3_apify_source_capture_ingest.json'), manifest)
writeFileSync(join(outRoot, 'top3_apify_source_capture_ingest.md'), [
  '# Top-3 Apify source capture ingest',
  '',
  `Generated: ${generatedAt}`,
  '',
  manifest.note,
  '',
  ...manifestRows.map(row => `- ${row.sku}: ${row.captured}/${row.requested} page captures, ${row.specialistCaptured} specialist items, ${row.missing} missing`)
].join('\n') + '\n', 'utf8')
console.log(`Ingested Apify captures for ${manifestRows.length} products`)
