import { readFile } from 'node:fs/promises'
import { resolve } from 'node:path'
import { createElementMap2MultiStageNameMapping, parseElementMap2MultiStageNameMapping, writeElementMap2MultiStageNameMapping } from '../src/facade/elementMap2.ts'
import { createNativeStageNamingEvidence, validateNativeNamingEvidence } from '../src/facade/nativeNamingEvidence.ts'

const root = resolve(new URL('..', import.meta.url).pathname)
const load = async (path) => JSON.parse(await readFile(resolve(root, path), 'utf8'))
const matrix = await load('config/compatibility-matrix.json')
const oracle = await load('config/freecad-composite-history-elementmap-oracle.json')
const fail = (message) => { throw new Error(`FreeCAD native naming evidence gate: ${message}`) }
const blockers = matrix.nativeOcctHistory?.historyProtocol?.namingEvidence?.exactBlockers
if (!Array.isArray(blockers) || blockers.length !== 2 || blockers.some((blocker) => blocker.includes('lacks the FreeCAD-linked') || blocker.includes('browser builder naming evidence transport') || blocker.includes('non-unique isomorphic'))) fail('exact blocker list must remove the closed production linkage and isomorphic provenance boundaries and retain two broader exactness boundaries.')
const featureLevels = matrix.facadeCapabilities?.geometry?.featureLevels
for (const feature of ['pad', 'pocket', 'revolution', 'groove', 'boolean']) {
  if (!featureLevels?.[feature] || featureLevels[feature].level !== 'compatible' || !Array.isArray(featureLevels[feature].exactBlockedBy) || featureLevels[feature].exactBlockedBy.length === 0) fail(`${feature} must have a non-exact capability level with explicit blockers.`)
}
let oracleStages = 0
let nativeEvidenceStages = 0
let nativeMappedNameStages = 0
let nativeIndexedNameStages = 0
let indexedNameOnlyStages = 0
let privateTokenEvidenceRequiredStages = 0
let privateTokenEvidenceCompleteStages = 0
let internalBuilderEvidenceStages = 0
let internalBuilderEvidenceMissingStages = 0
const builderStageType = /^(Part::(Fuse|Cut|Common|Extrusion|Revolution|Loft|Sweep|Fillet|Chamfer)|PartDesign::(Pad|Pocket|Revolution|Groove|AdditiveLoft|SubtractiveLoft|AdditivePipe|SubtractivePipe|Fillet|Chamfer|Draft|Thickness|Mirrored|MultiTransform|LinearPattern|PolarPattern|Hole))$/
for (const fixture of oracle.cases) for (const stage of fixture.stages ?? []) {
  oracleStages += 1
  if (!['final-shape-only', 'opaque-preserved', 'native-evidence', 'ambiguous', 'missing'].includes(stage.namingEvidenceStatus)) fail(`${fixture.id}/${stage.name} has no explicit naming evidence status.`)
  if (!stage.nativeEvidence || stage.nativeEvidence.stageId !== stage.name || stage.nativeEvidence.resultObjectId !== stage.name || stage.nativeEvidence.status !== stage.namingEvidenceStatus) fail(`${fixture.id}/${stage.name} has no stage-bound runtime naming evidence.`)
  const validation = validateNativeNamingEvidence(stage.nativeEvidence)
  if (!validation.valid) fail(`${fixture.id}/${stage.name} has invalid runtime naming evidence: ${validation.issues[0].path}: ${validation.issues[0].message}`)
  if (stage.namingEvidenceStatus === 'native-evidence') nativeEvidenceStages += 1
  if (stage.nativeEvidence.mappedNameApiEntries > 0) nativeMappedNameStages += 1
  if (stage.nativeEvidence.indexedNameApiEntries > 0) nativeIndexedNameStages += 1
  if (stage.nativeEvidence.indexedNameOnly === true) indexedNameOnlyStages += 1
  if (stage.nativeEvidence.privateTokenEvidenceRequired === true) privateTokenEvidenceRequiredStages += 1
  if (stage.nativeEvidence.privateTokenEvidenceComplete === true) privateTokenEvidenceCompleteStages += 1
  if (builderStageType.test(stage.typeId || '')) {
    if (stage.nativeEvidence.internalBuilderEvidence === true) internalBuilderEvidenceStages += 1
    else internalBuilderEvidenceMissingStages += 1
  }
}
if (oracleStages !== 219 || nativeEvidenceStages !== 219 || nativeIndexedNameStages !== 219) fail(`locked composite oracle must contain 219/219 stage-bound native indexed-name records, found native=${nativeEvidenceStages}, indexed=${nativeIndexedNameStages}, stages=${oracleStages}.`)
if (indexedNameOnlyStages + privateTokenEvidenceRequiredStages !== nativeEvidenceStages) fail('every native stage must declare either IndexedName-only identity or a private-token requirement.')
if (privateTokenEvidenceCompleteStages !== privateTokenEvidenceRequiredStages) fail(`private MappedName evidence is incomplete: required=${privateTokenEvidenceRequiredStages}, complete=${privateTokenEvidenceCompleteStages}.`)
if (internalBuilderEvidenceStages !== 42 || internalBuilderEvidenceMissingStages !== 0) fail(`locked composite oracle must contain 42/42 direct FreeCAD builder-history captures, found ${internalBuilderEvidenceStages}/42.`)
const exactFeatures = Object.values(featureLevels).filter((feature) => feature.level === 'exact').length
if (matrix.systemExactEvaluation?.exact !== false || matrix.systemExactEvaluation?.featureExactCount !== exactFeatures || JSON.stringify(matrix.systemExactEvaluation?.blockers) !== JSON.stringify(blockers)) fail('system exact evaluation must remain false and list the active native naming blockers.')
const table = { schemaVersion: 2, nativeVersion: 1, entries: [{ id: 1, flags: 0, relatedIds: [], data: 'native', postfix: '' }] }
const stage0 = createNativeStageNamingEvidence({ stageId: 'gate:0', resultObjectId: 'shape:0', status: 'native-evidence', stringHasher: table, mappedNames: [{ kind: 'face', resultIndex: 0, resultPersistentId: 'face:0', relation: 'generated', reference: { name: 'Face1', stringIds: [1] } }] })
const stage1 = createNativeStageNamingEvidence({ stageId: 'gate:1', resultObjectId: 'shape:1', status: 'ambiguous', stringHasher: table, mappedNames: [{ kind: 'face', resultIndex: 0, resultPersistentId: 'face:1', relation: 'ambiguous', reference: { name: 'Face1', stringIds: [1] }, sourceRefs: [{ objectId: 'shape:0', persistentId: 'face:0', stageId: 'gate:0' }], candidates: [{ objectId: 'a', persistentId: 'face:a' }, { objectId: 'b', persistentId: 'face:b' }] }] })
if (!validateNativeNamingEvidence(stage0).valid || !validateNativeNamingEvidence(stage1).valid) fail('runtime evidence validator rejected its golden native and ambiguous fixtures.')
const mapping = createElementMap2MultiStageNameMapping([stage0, stage1], [])
if (parseElementMap2MultiStageNameMapping(writeElementMap2MultiStageNameMapping(mapping)).stages[1].entries[0].status !== 'ambiguous') fail('multi-stage ElementMap2 mapping did not persist ambiguity.')
console.log(JSON.stringify({ status: 'freecad-native-naming-evidence-pass', cases: oracle.cases.length, oracleStages, nativeEvidenceStages, nativeIndexedNameStages, nativeMappedNameStages, indexedOnlyStages: indexedNameOnlyStages, privateTokenEvidenceRequiredStages, privateTokenEvidenceCompleteStages, internalBuilderEvidenceStages, internalBuilderEvidenceMissingStages, featureLevels: Object.fromEntries(Object.entries(featureLevels).map(([key, value]) => [key, value.level])), exactBlockers: blockers.length, ambiguousPersisted: true, systemFreecadExact: false, exactFeatures }, null, 2))
