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

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

type SourceSpec = {
  key: string
  dir: string
  required: string[]
  optional: string[]
  minFiles: number
  template: any
  note: string
}

const specs: SourceSpec[] = [
  {
    key: 'amazon',
    dir: join(sourcesRoot, 'amazon'),
    minFiles: 1,
    required: ['source', 'reviews'],
    optional: ['brand', 'sku', 'asin', 'productUrl', 'capturedAt'],
    note: 'JV and competitor Amazon reviews. Each review should include review_body/comment, rating, date, and URL when available.',
    template: {
      source: 'amazon', brand: 'Just Vitamins or competitor brand', sku: 'JV-D1000 or blank for competitor-only export', asin: '', productUrl: '', capturedAt: new Date().toISOString(),
      reviews: [{ review_title: '', review_body: '', rating: 5, date: '', helpful_count: 0, url: '' }]
    }
  },
  {
    key: 'trustpilot',
    dir: join(sourcesRoot, 'trustpilot'),
    minFiles: 1,
    required: ['source', 'brand', 'reviews'],
    optional: ['domain', 'capturedAt'],
    note: 'Trustpilot/brand-level review exports for JV or competitor brands.',
    template: {
      source: 'trustpilot', brand: 'Brand name', domain: '', capturedAt: new Date().toISOString(),
      reviews: [{ review_title: '', review_body: '', rating: 5, date: '', url: '' }]
    }
  },
  {
    key: 'reddit',
    dir: join(sourcesRoot, 'reddit'),
    minFiles: 1,
    required: ['source', 'query', 'items'],
    optional: ['capturedAt'],
    note: 'Reddit/social listening exports for collagen and supplement category research.',
    template: {
      source: 'reddit', query: 'collagen flavour chalky sweetness mixability', capturedAt: new Date().toISOString(),
      items: [{ subreddit: '', thread_url: '', post_title: '', comment_body: '', upvotes: 0, date: '' }]
    }
  }
]

function readJson(path: string) {
  return JSON.parse(readFileSync(path, 'utf8').replace(/^\uFEFF/, ''))
}
function listJson(dir: string) {
  if (!existsSync(dir)) return []
  return readdirSync(dir, { withFileTypes: true }).filter(entry => entry.isFile() && entry.name.endsWith('.json')).map(entry => join(dir, entry.name))
}
function csv(rows: any[], headers: string[]) {
  const esc = (value: any) => {
    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
  }
  return [headers.join(','), ...rows.map(row => headers.map(header => esc(row[header])).join(','))].join('\n') + '\n'
}
function validateItems(kind: string, data: any) {
  const issues: string[] = []
  const rows = kind === 'reddit' ? data.items : data.reviews
  if (!Array.isArray(rows) || rows.length === 0) issues.push(kind === 'reddit' ? 'items must be a non-empty array' : 'reviews must be a non-empty array')
  for (const [index, row] of (Array.isArray(rows) ? rows : []).entries()) {
    const text = kind === 'reddit' ? row.comment_body || row.post_title : row.review_body || row.comment || row.review_title
    if (!text || String(text).trim().length < 5) issues.push(`row ${index}: missing review/comment text`)
    if (kind !== 'reddit' && (row.rating === undefined || row.rating === null || row.rating === '')) issues.push(`row ${index}: missing rating`)
  }
  return issues
}

const rows: any[] = []
const details: any[] = []
for (const spec of specs) {
  mkdirSync(spec.dir, { recursive: true })
  writeFileSync(join(templateRoot, `${spec.key}-source-template.json`), JSON.stringify(spec.template, null, 2) + '\n', 'utf8')
  const files = listJson(spec.dir).filter(file => !file.includes(`${spec.key}-status.json`))
  if (files.length < spec.minFiles) {
    rows.push({ Source: spec.key, File: '', Status: 'missing', Issue: `Need at least ${spec.minFiles} JSON source drop(s) in ${spec.dir}`, Note: spec.note })
  }
  for (const file of files) {
    try {
      const data = readJson(file)
      const missing = spec.required.filter(field => data[field] === undefined || data[field] === null || data[field] === '' || (Array.isArray(data[field]) && data[field].length === 0))
      const itemIssues = validateItems(spec.key, data)
      const issues = [...missing.map(field => `missing required field ${field}`), ...itemIssues]
      rows.push({ Source: spec.key, File: file, Status: issues.length ? 'invalid' : 'valid', Issue: issues.join('; '), Note: spec.note })
      details.push({ source: spec.key, file, status: issues.length ? 'invalid' : 'valid', issues })
    } catch (error: any) {
      rows.push({ Source: spec.key, File: file, Status: 'invalid_json', Issue: error.message, Note: spec.note })
      details.push({ source: spec.key, file, status: 'invalid_json', issues: [error.message] })
    }
  }
}
const ready = rows.every(row => row.Status === 'valid') && specs.every(spec => listJson(spec.dir).length >= spec.minFiles)
const manifest = {
  generatedAt: new Date().toISOString(),
  ready,
  templateRoot,
  requiredSources: specs.map(spec => ({ key: spec.key, dir: spec.dir, minFiles: spec.minFiles, required: spec.required, optional: spec.optional, note: spec.note })),
  summary: specs.map(spec => ({ key: spec.key, fileCount: listJson(spec.dir).length, minFiles: spec.minFiles })),
  issues: rows.filter(row => row.Status !== 'valid'),
  details
}
writeFileSync(join(outRoot, 'source_drop_validation.json'), JSON.stringify(manifest, null, 2) + '\n', 'utf8')
writeFileSync(join(outRoot, 'source_drop_validation.csv'), csv(rows, ['Source', 'File', 'Status', 'Issue', 'Note']), 'utf8')
console.log(`Source drops ready: ${ready}`)
for (const item of manifest.summary) console.log(`${item.key}: ${item.fileCount}/${item.minFiles}`)
console.log(`Issues: ${manifest.issues.length}`)
if (!ready) process.exitCode = 1
