import { isDeepStrictEqual } from 'node:util'
import { readFile } 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-property-direction-roundtrip.json'), 'utf8'))
const fail = (message) => { throw new Error(`FreeCAD PropertyDirection roundtrip check failed: ${message}`) }
if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-direction-roundtrip' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyDirection') fail('baseline is invalid')

const initial = { x: 0, y: 0, z: 1 }
const target = { x: 0.25, y: -0.5, z: 1.5 }
const objectSet = [{ name: 'MirrorSource', typeId: 'Part::Box' }, { name: 'DirectionMirror', typeId: 'Part::Mirroring' }]
for (const [phase, snapshot] of [['nativeInitial', report.nativeInitial], ['nativeReopened', report.nativeAfter?.reopened], ['nativeResaved', report.nativeAfter?.resaved], ['nativeRepeatReopened', report.nativeRepeat?.reopened], ['nativeRepeatResaved', report.nativeRepeat?.resaved]]) {
  if (snapshot?.object?.name !== 'DirectionMirror' || snapshot.object.typeId !== 'Part::Mirroring' || snapshot.object.propertyTypeId !== 'App::PropertyDirection' || !isDeepStrictEqual(snapshot.object.propertyStatus, []) || !isDeepStrictEqual(snapshot.object.editorMode, []) || !isDeepStrictEqual(snapshot.object.state, ['Up-to-date']) || snapshot.object.statusString !== 'Valid' || !isDeepStrictEqual(snapshot.objectSet, objectSet)) fail(`${phase} native object semantics are incomplete`)
  const shape = snapshot.object.shape
  if (shape?.isNull !== false || shape.valid !== true || shape.shapeType !== 'Solid' || shape.solids !== 1 || shape.faces !== 6 || shape.edges !== 12 || shape.vertices !== 8 || shape.area !== 52 || shape.volume !== 24 || !Array.isArray(shape.bounds) || shape.bounds.length !== 6 || !/^[0-9a-f]{64}$/.test(shape.brepSha256)) fail(`${phase} native Shape evidence is incomplete`)
}
if (!isDeepStrictEqual(report.nativeInitial.object.value, initial) || !isDeepStrictEqual(report.nativeAfter.reopened.object.value, target) || !isDeepStrictEqual(report.nativeAfter.resaved.object.value, target) || !isDeepStrictEqual(report.nativeRepeat.reopened.object.value, target) || !isDeepStrictEqual(report.nativeRepeat.resaved.object.value, target)) fail('native direction values drifted')
let webBefore
let webAfter
try {
  webBefore = JSON.parse(report.web.before?.value)
  webAfter = JSON.parse(report.web.after?.value)
} catch { fail('Web Direction values are not structured JSON') }
if (report.web.before?.typeId !== 'App::PropertyDirection' || report.web.before?.element !== 'PropertyVector' || !isDeepStrictEqual(webBefore, initial) || report.web.after?.typeId !== 'App::PropertyDirection' || report.web.after?.element !== 'PropertyVector' || !isDeepStrictEqual(webAfter, target) || report.web.targetMarkedTouched !== true || report.web.webOutputMatches !== true || report.web.objectSetPreserved !== true || report.web.semanticObjectsPreserved !== true || report.web.opaqueEntriesPreserved !== true || !Number.isSafeInteger(report.web.opaquePathsPreserved) || report.web.opaquePathsPreserved < 1) fail('Web edit did not preserve native archive semantics')
if (!isDeepStrictEqual(report.classification?.requestedValue, target) || !isDeepStrictEqual(report.classification.webValue, target) || !isDeepStrictEqual(report.classification.reopenedValue, target) || !isDeepStrictEqual(report.classification.resavedValue, target) || report.classification.nativeOutputMatches !== true || report.classification.nativeShapeChanged !== true || report.classification.nativeShapeStructureStable !== true || report.classification.nativeBrepReserialized !== true || report.classification.nativeBrepEvolutionReproduced !== true || report.classification.nativeAllowedEvolution?.classification !== 'native-allowed-evolution' || report.classification.nativeAllowedEvolution.dimension !== 'brep-serialization' || !report.classification.nativeAllowedEvolution.reason.includes('reserializes') || report.classification.unknownSemanticDrift !== false || report.classification.zeroUnknownDrift !== true) fail('round-trip classification is not exact for PropertyDirection')
const shapeStructure = ({ brepSha256: _brepSha256, ...shape }) => shape
if (report.nativeInitial.object.shape.brepSha256 === report.nativeAfter.reopened.object.shape.brepSha256 || isDeepStrictEqual(report.nativeInitial.object.shape.bounds, report.nativeAfter.reopened.object.shape.bounds)) fail('native Direction did not change Shape geometry')
if (!isDeepStrictEqual(shapeStructure(report.nativeAfter.reopened.object.shape), shapeStructure(report.nativeAfter.resaved.object.shape)) || !isDeepStrictEqual(shapeStructure(report.nativeAfter.reopened.object.shape), shapeStructure(report.nativeRepeat.reopened.object.shape)) || !isDeepStrictEqual(shapeStructure(report.nativeAfter.reopened.object.shape), shapeStructure(report.nativeRepeat.resaved.object.shape))) fail('native Shape structure drifted across resave repetitions')
if (report.nativeAfter.reopened.object.shape.brepSha256 === report.nativeAfter.resaved.object.shape.brepSha256 || report.nativeAfter.reopened.object.shape.brepSha256 !== report.nativeRepeat.reopened.object.shape.brepSha256 || report.nativeAfter.resaved.object.shape.brepSha256 !== report.nativeRepeat.resaved.object.shape.brepSha256) fail('native BREP serialization evolution was not reproduced')
for (const archive of Object.values(report.archives ?? {})) if (!archive?.path || !Number.isSafeInteger(archive.bytes) || archive.bytes <= 0 || !/^[0-9a-f]{64}$/.test(archive.sha256)) fail('archive evidence is incomplete')

console.log(JSON.stringify({ status: 'freecad-property-direction-roundtrip-pass', values: { nativeInitial: report.nativeInitial.object.value, webEdited: report.classification.webValue, nativeReopened: report.classification.reopenedValue, nativeResaved: report.classification.resavedValue }, shapeChanged: report.classification.nativeShapeChanged, shapeStructureStable: report.classification.nativeShapeStructureStable, nativeAllowedEvolution: report.classification.nativeAllowedEvolution, opaquePathsPreserved: report.web.opaquePathsPreserved, zeroUnknownDrift: report.classification.zeroUnknownDrift }, null, 2))
