import { createHash } from 'node:crypto'
import { execFileSync } from 'node:child_process'
import { existsSync } from 'node:fs'
import { readFile } from 'node:fs/promises'
import { resolve } from 'node:path'

const root = resolve(new URL('..', import.meta.url).pathname)
const evidence = JSON.parse(await readFile(resolve(root, 'config/opencamlib-wasm-artifact.json'), 'utf8'))
if (evidence.schemaVersion !== 1 || evidence.status !== 'pass') throw new Error('OpenCAMLib artifact evidence is not passing.')
const source = resolve(root, evidence.openCamLib.sourcePath)
const revision = execFileSync('git', ['-C', source, 'rev-parse', 'HEAD'], { encoding: 'utf8' }).trim()
if (revision !== evidence.openCamLib.sourceRevision) throw new Error(`OpenCAMLib revision drift: ${revision}`)
const artifact = await readFile(resolve(root, evidence.openCamLib.artifact))
const digest = createHash('sha256').update(artifact).digest('hex')
if (artifact.byteLength !== evidence.openCamLib.byteLength || digest !== evidence.openCamLib.sha256) throw new Error('OpenCAMLib WASM artifact size or digest mismatch.')
const binding = await readFile(resolve(root, evidence.openCamLib.bindingSource), 'utf8')
for (const symbol of ['PathDropCutter', 'AdaptivePathDropCutter', 'Waterline', 'AdaptiveWaterline', 'CylCutter', 'BallCutter']) {
  if (!binding.includes(`\"${symbol}\"`)) throw new Error(`OpenCAMLib binding is missing ${symbol}.`)
}
const artifactText = artifact.toString('utf8')
if (!artifactText.includes('data:application/octet-stream;base64,') || !artifactText.includes('WebAssembly.instantiate')) throw new Error('OpenCAMLib artifact does not contain an embedded executable WASM module.')
if (evidence.solidRemoval.backend !== 'bitbybit-occt-wasm' || evidence.solidRemoval.nativeSolid !== true || evidence.solidRemoval.freeCadNativeEquivalent !== false) throw new Error('OCCT solid-removal boundary is invalid.')
if (evidence.camotics.status !== 'native-host-available' || evidence.camotics.backend !== 'camotics-native-host-qt5-tpl' || evidence.camotics.nativeExecutable !== true || evidence.camotics.nativeBuildStatus !== 'verified-qt5-gui-tpl' || evidence.camotics.nativeGuiPath !== 'CAMotics/camotics' || evidence.camotics.nativeTplPath !== 'CAMotics/tplang' || evidence.camotics.browserExecutable !== false || evidence.camotics.browserWasmKernelExecutable !== true || evidence.camotics.browserWasmKernel?.fullCamoticsProgram !== false || evidence.camotics.browserWasmKernel.gcodeParserIncluded !== false) throw new Error('CAMotics native GUI/TPL/WASM capability boundary is invalid.')
const camoticsSource = resolve(root, evidence.camotics.sourcePath)
const camoticsRevision = execFileSync('git', ['-C', camoticsSource, 'rev-parse', 'HEAD'], { encoding: 'utf8' }).trim()
if (camoticsRevision !== evidence.camotics.sourceRevision) throw new Error(`CAMotics revision drift: ${camoticsRevision}`)
for (const sourceFile of evidence.camotics.sourceFiles) if (!existsSync(resolve(root, sourceFile))) throw new Error(`CAMotics source evidence is missing ${sourceFile}.`)
const camoticsGenerator = await readFile(resolve(root, 'CAMotics/src/gcode/machine/GCodeMachine.cpp'), 'utf8')
for (const method of ['start', 'changeTool', 'setFeed', 'move', 'end']) if (!camoticsGenerator.includes(`GCodeMachine::${method}`)) throw new Error(`CAMotics G-code generator source is missing ${method}.`)
for (const nativeArtifact of [evidence.camotics.nativeGuiPath, evidence.camotics.nativeTplPath]) if (!existsSync(resolve(root, nativeArtifact))) throw new Error(`CAMotics native artifact is missing: ${nativeArtifact}`)
if (!existsSync(resolve(root, evidence.camotics.browserWasmKernel.artifact))) throw new Error('CAMotics browser WASM artifact is missing.')
if (!existsSync(resolve(root, evidence.camotics.nativeArtifactEvidence))) throw new Error('CAMotics native artifact evidence is missing.')
if (evidence.camotics.generationAuthority !== 'camotics-source-stage' || evidence.camotics.parserAuthority !== 'linuxcnc-wasm' || evidence.camotics.camoticsParsesCanonicalGcode !== false || evidence.camotics.pipeline?.canonicalGcodeAuthority !== 'linuxcnc-wasm' || evidence.camotics.pipeline?.camoticsSemanticParser !== false || evidence.camotics.pipeline?.linuxcncWasmExecution !== 'handoff-required') throw new Error('CAMotics/LinuxCNC pipeline authority is invalid.')
const nativeEvidence = JSON.parse(await readFile(resolve(root, evidence.camotics.nativeArtifactEvidence), 'utf8'))
if (nativeEvidence.schemaVersion !== 2 || nativeEvidence.status !== 'pass' || nativeEvidence.source.revision !== evidence.camotics.sourceRevision || nativeEvidence.cbang.revision !== evidence.camotics.cbangRevision || nativeEvidence.build.withGui !== true || nativeEvidence.build.withTpl !== true || nativeEvidence.guiSmoke.status !== 'pass') throw new Error('CAMotics native GUI/TPL evidence is missing or stale.')
console.log(JSON.stringify({ status: 'opencamlib-wasm-pass', sourceRevision: revision, artifactBytes: artifact.byteLength, sha256: digest, algorithms: evidence.openCamLib.algorithms, solidRemoval: evidence.solidRemoval, camoticsRevision, camotics: evidence.camotics, nativeEvidence: { artifacts: nativeEvidence.artifacts, tplTests: nativeEvidence.tplTests, guiSmoke: nativeEvidence.guiSmoke } }, null, 2))
