import { createHash } from 'node:crypto'
import { readFile, stat } from 'node:fs/promises'
import { resolve } from 'node:path'
import { FREECAD_NAMING_CALLBACKS, FREECAD_NAMING_OPERATIONS } from './freecad-naming-production-matrix.mjs'

const root = resolve(new URL('..', import.meta.url).pathname)
const fail = (message) => { throw new Error(`FreeCAD production naming verification failed: ${message}`) }
const checkReport = async (reportName, runtime, artifactRoot) => {
  const report = JSON.parse(await readFile(resolve(root, 'config', reportName), 'utf8'))
  if (report.status !== 'pass' || report.runtime !== runtime || report.implementation !== 'freecad-linked' || report.productionWorkerLinked !== true || report.systemExact !== false) fail(`${reportName} has an invalid production boundary.`)
  if (JSON.stringify(report.callbacks) !== JSON.stringify(FREECAD_NAMING_CALLBACKS)) fail(`${reportName} callback list is incomplete.`)
  if (JSON.stringify(report.operations) !== JSON.stringify(FREECAD_NAMING_OPERATIONS) || report.cases?.length !== FREECAD_NAMING_OPERATIONS.length) fail(`${reportName} operation matrix is incomplete.`)
  if (report.cases.some((entry, index) => {
    const native = entry.selectedRecords > 0
    return entry.operation !== FREECAD_NAMING_OPERATIONS[index]
      || entry.status !== 'pass'
      || entry.provenanceResults < 1
      || entry.provenanceResults !== entry.selectedRecords + entry.ambiguousResults
      || entry.externallySourcedRecords < 1
      || entry.internalRecordsExcluded < 0
      || entry.externallySourcedRecords + entry.internalRecordsExcluded !== entry.historyRecords
      || entry.duplicateRecordsCollapsed < 0
      || entry.modifiedRelationPrecedence < 0
      || entry.callbackExecuted !== native
      || entry.mappedNames !== entry.selectedRecords
      || (native && (entry.stringHasherEntries < 0 || entry.elementMaps < 1 || !['native-evidence', 'mixed-native-and-ambiguous'].includes(entry.namingStatus)))
      || (!native && (entry.ambiguousResults < 1 || entry.stringHasherEntries !== 0 || entry.elementMaps !== 0 || entry.namingStatus !== 'ambiguous'))
  })) fail(`${reportName} contains an invalid operation result.`)
  const callbackCases = report.cases.filter(({ callbackExecuted }) => callbackExecuted).length
  const ambiguityOnlyCases = report.cases.filter(({ namingStatus }) => namingStatus === 'ambiguous').length
  if (report.callbackExecutedCases !== callbackCases || report.ambiguityOnlyCases !== ambiguityOnlyCases || callbackCases < 1 || callbackCases + ambiguityOnlyCases !== FREECAD_NAMING_OPERATIONS.length) fail(`${reportName} has invalid callback/ambiguity partitioning.`)
  if (report.isomorphicCorpus?.status !== 'pass' || report.isomorphicCorpus.fixture !== 'coincident-equal-boxes' || report.isomorphicCorpus.uniqueResults !== 0 || report.isomorphicCorpus.ambiguousResults < 1 || report.isomorphicCorpus.arrayOrderFallbackUsed !== false || report.isomorphicCorpus.candidateSets?.some(({ candidates }) => candidates.length < 2)) fail(`${reportName} is missing its symmetric native-provenance corpus.`)
  if (report.invalidHistoryRejected !== true || report.chainedStage?.mappedNames < 1 || report.chainedStage?.stringHasherEntries < 2) fail(`${reportName} is missing chained or fail-closed evidence.`)
  for (const artifact of report.artifacts ?? []) {
    const path = resolve(root, artifactRoot, artifact.name)
    const [content, bytes] = await Promise.all([readFile(path), stat(path).then(({ size }) => size)])
    if (bytes !== artifact.bytes || createHash('sha256').update(content).digest('hex') !== artifact.sha256) fail(`${reportName} is stale for ${artifact.name}.`)
  }
  if (report.artifacts?.length !== 3) fail(`${reportName} must lock JS, WASM and DATA.`)
  const harnessPath = resolve(root, report.harness?.path ?? '')
  const [harnessContent, harnessBytes] = await Promise.all([readFile(harnessPath), stat(harnessPath).then(({ size }) => size)])
  if (report.harness?.path !== 'scripts/freecad-naming-production-matrix.mjs' || harnessBytes !== report.harness.bytes || createHash('sha256').update(harnessContent).digest('hex') !== report.harness.sha256) fail(`${reportName} is stale for the shared production harness.`)
  return { runtime, cases: report.cases.length, generatedAt: report.generatedAt }
}

const requestedRuntime = process.argv.find((argument) => argument.startsWith('--runtime='))?.slice('--runtime='.length) ?? 'all'
if (!['all', 'node', 'chrome'].includes(requestedRuntime)) fail(`unsupported runtime ${requestedRuntime}.`)
const specs = [
  ['freecad-naming-production-verification.json', 'node', 'native/occt-history/dist'],
  ['chrome-freecad-naming-production-verification.json', 'chrome', 'public/native/occt-history'],
].filter(([, runtime]) => requestedRuntime === 'all' || runtime === requestedRuntime)
const reports = []
for (const [reportName, runtime, artifactRoot] of specs) reports.push(await checkReport(reportName, runtime, artifactRoot))
console.log(JSON.stringify({ status: 'freecad-production-naming-pass', implementation: 'freecad-linked', callbacks: FREECAD_NAMING_CALLBACKS, operations: FREECAD_NAMING_OPERATIONS.length, reports, systemExact: false }, null, 2))
