import { createHash } from 'node:crypto'
import { readFile, stat } from 'node:fs/promises'
import { resolve } from 'node:path'

const root = resolve(new URL('..', import.meta.url).pathname)
const report = JSON.parse(await readFile(resolve(root, 'config/freecad-isomorphic-provenance-verification.json'), 'utf8'))
const fail = (message) => { throw new Error(`FreeCAD isomorphic provenance check failed: ${message}`) }
if (report.schemaVersion !== 1 || report.status !== 'pass' || report.runtime !== 'node' || report.implementation !== 'freecad-linked' || report.productionWorkerLinked !== true || report.systemExact !== false) fail('report boundary is invalid')
const symmetric = report.cases?.symmetricCommon
if (symmetric?.status !== 'ambiguous' || symmetric.stable !== 0 || symmetric.ambiguous < 1 || symmetric.candidates < symmetric.ambiguous * 2 || symmetric.persistedCandidateSets !== true) fail('symmetric Common evidence is incomplete')
const mixed = report.cases?.mixedCut
if (mixed?.status !== 'ambiguous' || mixed.stable < 1 || mixed.ambiguous < 1 || mixed.elementMaps < 1) fail('mixed Cut evidence is incomplete')
const downstream = report.cases?.downstreamRotate
if (downstream?.status !== 'ambiguous' || downstream.ambiguous < 1 || !downstream.candidateObjects?.includes('cut-object') || !downstream.candidateObjects?.includes('cut-tool')) fail('cross-feature candidate propagation is incomplete')
const longChain = report.cases?.longChain
if (JSON.stringify(longChain?.operations) !== '["cut","rotate","fillet","mirrored","linear-pattern"]' || longChain.stages?.length !== 5 || longChain.persistedFinalEvidence !== true || longChain.referencedCandidateObjectsRetained !== true || longChain.stringHasherMonotonic !== true) fail('long-chain naming evidence is incomplete')
for (const [index, stage] of longChain.stages.entries()) {
  if (stage.status !== 'ambiguous' || stage.stable < 1 || stage.ambiguous < 1 || stage.candidates < stage.ambiguous * 2 || (index > 0 && stage.persistedInputEvidence !== true)) fail(`long-chain stage ${String(stage.operation)} did not preserve stable and ambiguous provenance`)
  if (index > 0 && (stage.referencedCandidateObjectsRetained !== true || stage.elementMaps < 1 || stage.referencedInputCandidateObjects?.some((objectId) => !stage.candidateObjects?.includes(objectId)))) fail(`long-chain stage ${String(stage.operation)} lost referenced provenance or ElementMap2 evidence`)
  if (index > 1 && stage.stringHasherEntries < longChain.stages[index - 1].stringHasherEntries) fail(`long-chain stage ${String(stage.operation)} regressed StringHasher state`)
}
if (report.fcstdAmbiguityRejected !== true) fail('FCStd fail-closed evidence is absent')
if (JSON.stringify(report.fcstdStableLinkRoundtrip?.subElements) !== '["Face1"]' || report.fcstdStableLinkRoundtrip.inspectRewritePreserved !== true || report.fcstdStableLinkRoundtrip.nativeDesktopResaveCovered !== false) fail('FCStd stable LinkSub persistence boundary is incomplete')
for (const artifact of report.artifacts ?? []) {
  const path = resolve(root, 'native/occt-history/dist', 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(`report is stale for ${artifact.name}`)
}
if (report.artifacts?.length !== 3) fail('JS/WASM/DATA artifact lock is incomplete')
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/run-freecad-isomorphic-provenance.ts' || harnessBytes !== report.harness.bytes || createHash('sha256').update(harnessContent).digest('hex') !== report.harness.sha256) fail('report is stale for its executable harness')
console.log(JSON.stringify({ status: 'freecad-isomorphic-provenance-pass', symmetricAmbiguities: symmetric.ambiguous, downstreamAmbiguities: downstream.ambiguous, longChainStages: longChain.stages.length, fcstdAmbiguityRejected: true, fcstdStableLinkRoundtrip: true, systemExact: false }, null, 2))
