#!/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')
mkdirSync(outRoot, { 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'
}

const generatedAt = new Date().toISOString()
const verification = readJson(join(outRoot, 'handoff_verification_run.json'), { checks: [] })
const preflight = readJson(join(outRoot, 'reviewer_input_preflight.json'), { blockingRows: [] })
const ownerResponses = readJson(join(outRoot, 'owner_response_intake.json'), { rows: [] })
const evidenceDossier = readJson(join(outRoot, 'handoff_evidence_dossier.json'), { requirements: [] })

const gateMeta: Record<string, any> = {
  export_content: { owner: 'Dashboard', lane: 'Export generation', inputs: ['data/content/products/', 'data/content/metaobjects.json', 'data/content/smart-collections.json'], unblock: 'Already passing; rerun after approvals or content changes.', upstream: [] },
  validate_assets: { owner: 'Dashboard / design', lane: 'Asset file presence', inputs: ['C:/Users/uldvs/OneDrive/Desktop/jv-assets', 'content_population_exports/asset_manifest_validation.*'], unblock: 'Already passing for file presence; human image approval is separate.', upstream: [] },
  validate_template: { owner: 'Dashboard', lane: 'Matrixify template schema', inputs: ['Just Vitamins - Content Population Templates workbook', 'content_population_exports/*matrixify.csv'], unblock: 'Already passing; rerun after emitter changes.', upstream: [] },
  source_request_pack: { owner: 'Research / compliance / image', lane: 'Source request pack', inputs: ['content_population_exports/source_request_*'], unblock: 'Already passing; use as owner request evidence.', upstream: [] },
  validate_sources: { owner: 'Research', lane: 'Source drop validation', inputs: ['data/sources/amazon/', 'data/sources/trustpilot/', 'data/sources/reddit/'], unblock: 'Already passing for current source drops; more source evidence may still be needed by owners.', upstream: [] },
  validate_claims: { owner: 'Compliance', lane: 'Claims library validation', inputs: ['data/content/claims-library.json'], unblock: 'Already passing structurally; remaining blank clinical claims still need decisions or source-backed refs.', upstream: [] },
  clinical_blank_decisions: { owner: 'Compliance owner / Umar', lane: 'Compliance blank/source-backed claim decisions', inputs: ['data/content/compliance/clinical-blank-decisions.csv'], unblock: 'Fill approved_blank rows with approvedBy, approvedAt, rationale, constraintsAcknowledged=yes or provide source-backed claim refs and rerun claims sync.', upstream: ['Compliance clinical blanks'] },
  intelligence_queue: { owner: 'Dashboard intelligence lane', lane: 'Full catalogue intelligence coverage', inputs: ['data/intelligence/**'], unblock: 'Already passing; rerun if product scope changes.', upstream: [] },
  product_approval_decisions: { owner: 'Umar / JV reviewer', lane: 'Product approval decisions', inputs: ['data/content/approvals/product-approval-decisions.csv'], unblock: 'Fill approve_all decisions with approver, timestamp, review evidence, and all acknowledgements.', upstream: ['Product approval decisions'] },
  product_approval_review_packet: { owner: 'Umar / JV reviewer', lane: 'Product approval review packet', inputs: ['data/content/approvals/product-approval-decisions.csv', 'content_population_exports/product_approval_review_packet.*'], unblock: 'Clears only after product approvals validate and no product remains blocked.', upstream: ['Product approval decisions'] },
  handoff_actions: { owner: 'Project owner', lane: 'Handoff action closure', inputs: ['content_population_exports/handoff_action_plan.*'], unblock: 'Closes after compliance, approval, staging, and provider owner lanes are resolved.', upstream: ['Compliance clinical blanks', 'Product approval decisions', 'Staging import evidence', 'DataForSEO provider response', 'DataForSEO spend approval'] },
  executive_decision_brief: { owner: 'Project owner / Umar / Lewis / Euan', lane: 'Executive decision closure', inputs: ['content_population_exports/executive_decision_brief.*'], unblock: 'Closes after named decisions have recorded evidence and owners.', upstream: ['Compliance clinical blanks', 'Product approval decisions', 'Staging import evidence', 'DataForSEO provider response'] },
  staging_handoff_packet: { owner: 'Lewis/Euan + dashboard owner', lane: 'Staging handoff readiness', inputs: ['content_population_exports/staging_handoff_packet.*', 'data/staging/**'], unblock: 'Import files are present; real import/PDP/cutover evidence must be recorded.', upstream: ['Staging import evidence', 'Staging PDP spot checks', 'Staging cutover approval'] },
  staging_evidence: { owner: 'Lewis/Euan + dashboard owner', lane: 'Staging evidence', inputs: ['data/staging/import-logs/', 'data/staging/pdp-checks/', 'data/staging/cutover-approval.json'], unblock: 'Save clean import logs, at least 5 real PDP spot checks, and signed cutover approval.', upstream: ['Staging import evidence', 'Staging PDP spot checks', 'Staging cutover approval'] },
  staging_checklist: { owner: 'Lewis/Euan + dashboard owner', lane: 'Staging checklist', inputs: ['content_population_exports/staging_import_checklist.*', 'data/staging/**'], unblock: 'Clears after staging evidence validator passes and preflight/import/PDP/cutover checks are recorded.', upstream: ['Staging import evidence', 'Staging PDP spot checks', 'Staging cutover approval'] },
  delivery_index: { owner: 'Project owner', lane: 'Delivery packet completeness', inputs: ['content_population_exports/delivery_index.*'], unblock: 'Already passing; only proves files exist, not final readiness.', upstream: [] },
  content_audit: { owner: 'Dashboard / project owner', lane: 'Final content audit', inputs: ['content_population_exports/content_population_readiness.*'], unblock: 'Final aggregate gate; clears after compliance and approvals resolve remaining export blockers.', upstream: ['Compliance clinical blanks', 'Product approval decisions'] }
}

function preflightMatches(meta: any, row: any) {
  const areas = meta.upstream || []
  return areas.some((area: string) => row.Area === area)
}
function responseMatches(meta: any, row: any) {
  return row.Lane === meta.lane || row.Owner === meta.owner || String(meta.lane || '').includes(row.Lane) || String(row.Lane || '').includes(meta.lane)
}

const rows = (verification.checks || []).map((check: any, index: number) => {
  const meta = gateMeta[check.Name] || { owner: 'Project owner', lane: check.Name, inputs: [], unblock: 'Inspect command output and rerun the named command.', upstream: [] }
  const preflightRows = (preflight.blockingRows || []).filter((row: any) => preflightMatches(meta, row))
  const responseRows = (ownerResponses.rows || []).filter((row: any) => responseMatches(meta, row))
  const requirementRows = (evidenceDossier.requirements || []).filter((req: any) => String(req.RemainingWork || '').includes(meta.owner) || String(req.Requirement || '').toLowerCase().includes(String(meta.lane || '').split(' ')[0]?.toLowerCase()))
  const blockerEvidence = preflightRows.length
    ? preflightRows.map((row: any) => `${row.Area}: ${row.Evidence}`).join(' | ')
    : check.Status === 'pass'
      ? String(check.Stdout || '').split('\n').slice(0, 2).join(' | ')
      : String(check.Stdout || check.Stderr || '').split('\n').slice(0, 2).join(' | ')
  return {
    Sequence: index + 1,
    Gate: check.Name,
    Status: check.Status,
    ExitCode: check.ExitCode,
    Command: check.Command,
    Owner: meta.owner,
    Lane: meta.lane,
    Inputs: meta.inputs,
    UpstreamBlockers: meta.upstream,
    BlockerEvidence: blockerEvidence,
    OwnerResponseStatus: responseRows.map((row: any) => `${row.Lane}: ${row.Status}`).join(' | ') || (check.Status === 'pass' ? 'not needed while passing' : 'no owner response recorded'),
    EvidenceDossierLinks: requirementRows.map((row: any) => row.Requirement),
    UnblockInstruction: meta.unblock,
    NextCommand: check.Command
  }
})

const blockedRows = rows.filter(row => row.Status !== 'pass')
const ownerGroups = [...new Set(blockedRows.map(row => row.Owner))].map(owner => ({
  Owner: owner,
  BlockedGates: blockedRows.filter(row => row.Owner === owner).length,
  Gates: blockedRows.filter(row => row.Owner === owner).map(row => row.Gate).join(' | '),
  FirstAction: blockedRows.find(row => row.Owner === owner)?.UnblockInstruction || ''
}))
const manifest = {
  generatedAt,
  ready: blockedRows.length === 0,
  purpose: 'Dependency map from master verifier gates to the owner inputs and evidence that unblock them. It prevents rerunning gates blindly and keeps owner/external blockers explicit.',
  counts: {
    gates: rows.length,
    passing: rows.filter(row => row.Status === 'pass').length,
    blocked: blockedRows.length,
    ownersWithBlockedGates: ownerGroups.length
  },
  rows,
  blockedRows,
  ownerGroups,
  files: {
    markdown: 'content_population_exports/handoff_gate_dependency_map.md',
    json: 'content_population_exports/handoff_gate_dependency_map.json',
    csv: 'content_population_exports/handoff_gate_dependency_map.csv',
    ownerCsv: 'content_population_exports/handoff_gate_dependency_by_owner.csv'
  }
}

writeFileSync(join(outRoot, 'handoff_gate_dependency_map.json'), JSON.stringify(manifest, null, 2) + '\n', 'utf8')
writeFileSync(join(outRoot, 'handoff_gate_dependency_map.csv'), csv(rows, ['Sequence', 'Gate', 'Status', 'ExitCode', 'Command', 'Owner', 'Lane', 'Inputs', 'UpstreamBlockers', 'BlockerEvidence', 'OwnerResponseStatus', 'EvidenceDossierLinks', 'UnblockInstruction', 'NextCommand']), 'utf8')
writeFileSync(join(outRoot, 'handoff_gate_dependency_by_owner.csv'), csv(ownerGroups, ['Owner', 'BlockedGates', 'Gates', 'FirstAction']), 'utf8')
writeFileSync(join(outRoot, 'handoff_gate_dependency_map.md'), [
  '# Handoff gate dependency map',
  '',
  `Generated: ${generatedAt}`,
  '',
  `Ready: **${manifest.ready ? 'YES' : 'NO'}**`,
  `Gates passing: ${manifest.counts.passing}/${manifest.counts.gates}`,
  `Blocked gates: ${manifest.counts.blocked}`,
  `Owners with blocked gates: ${manifest.counts.ownersWithBlockedGates}`,
  '',
  'This map ties each master verifier gate to the actual owner input needed to unblock it. It does not approve content, create staging proof, or authorize provider spend.',
  '',
  '## Blocked gates by owner',
  '| Owner | Blocked gates | Gates | First action |',
  '|---|---:|---|---|',
  ...ownerGroups.map(row => `| ${row.Owner} | ${row.BlockedGates} | ${row.Gates.replace(/\|/g, '/')} | ${row.FirstAction.replace(/\|/g, '/')} |`),
  '',
  '## Blocked gates',
  ...blockedRows.map(row => `- **${row.Gate}** (${row.Owner}): ${row.BlockerEvidence || row.UnblockInstruction}. Next: ${row.UnblockInstruction}`),
  '',
  '## Final rule',
  'Use this map to route work, then rerun the named gate commands. Final readiness still requires `bun run verify:handoff` to pass.',
  ''
].join('\n'), 'utf8')

console.log(`Handoff gate dependency map ready: ${manifest.ready}`)
console.log(`Gates passing: ${manifest.counts.passing}/${manifest.counts.gates}`)
console.log(`Blocked gates: ${manifest.counts.blocked}`)
if (!manifest.ready) process.exitCode = 1
