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-colorlist-roundtrip.json'), 'utf8'))
const fail = (message) => { throw new Error(`FreeCAD PropertyColorList roundtrip check failed: ${message}`) }
if (report.schemaVersion !== 1 || report.status !== 'pass' || report.baselineId !== 'freecad-1.1.1-property-colorlist-roundtrip' || report.freecadVersion !== '1.1.1' || report.gitCommit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d' || report.propertyType !== 'App::PropertyColorList') fail('baseline is invalid')
const initial = [[17 / 255, 34 / 255, 51 / 255, 68 / 255]]
const target = [
  [51 / 255, 102 / 255, 153 / 255, 204 / 255],
  [17 / 255, 34 / 255, 51 / 255, 68 / 255],
]
const approximately = (value, expected) => Array.isArray(value) && value.length === expected.length && value.every((color, colorIndex) => Array.isArray(color) && color.length === 4 && color.every((channel, channelIndex) => typeof channel === 'number' && Math.abs(channel - expected[colorIndex][channelIndex]) <= 1e-7))
for (const [phase, snapshot] of [['nativeInitial', report.nativeInitial], ['nativeReopened', report.nativeAfter?.reopened], ['nativeResaved', report.nativeAfter?.resaved]]) {
  if (snapshot?.object?.typeId !== 'App::FeatureTest' || snapshot.object.propertyTypeId !== 'App::PropertyColorList' || !isDeepStrictEqual(snapshot.object.propertyStatus, []) || !isDeepStrictEqual(snapshot.object.editorMode, []) || snapshot.object.hasShapeProperty !== false || !isDeepStrictEqual(snapshot.objectSet, [{ name: 'ColorListProbe', typeId: 'App::FeatureTest' }])) fail(`${phase} native object semantics are incomplete`)
}
if (!approximately(report.nativeInitial.object.value, initial) || !approximately(report.nativeAfter.reopened.object.value, target) || !approximately(report.nativeAfter.resaved.object.value, target) || !isDeepStrictEqual(report.nativeAfter.reopened.object.value, report.nativeAfter.resaved.object.value)) fail('native initial/reopen/resave values drifted')
let webBefore
let webAfter
try {
  webBefore = JSON.parse(report.web.before?.value)
  webAfter = JSON.parse(report.web.after?.value)
} catch { fail('Web values are not structured ColorList JSON') }
if (report.web.before?.typeId !== 'App::PropertyColorList' || report.web.before?.element !== 'ColorList' || !approximately(webBefore, initial) || report.web.after?.typeId !== 'App::PropertyColorList' || report.web.after?.element !== 'ColorList' || !approximately(webAfter, target) || report.web.resource?.path !== 'ColourList' || report.web.resource.pathPreserved !== true || report.web.resource.beforeBytes !== 8 || report.web.resource.afterBytes !== 12 || report.web.resource.changed !== 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 (!approximately(report.classification?.requestedValue, target) || !approximately(JSON.parse(report.classification.webValue), target) || !approximately(report.classification.reopenedValue, target) || !approximately(report.classification.resavedValue, target) || report.classification.nativeOutputMatches !== true || report.classification.unknownSemanticDrift !== false || report.classification.zeroUnknownDrift !== true) fail('round-trip classification is not exact for PropertyColorList')
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-colorlist-roundtrip-pass', values: { nativeInitial: report.nativeInitial.object.value, webEdited: JSON.parse(report.classification.webValue), nativeReopened: report.classification.reopenedValue, nativeResaved: report.classification.resavedValue }, resource: report.web.resource, opaquePathsPreserved: report.web.opaquePathsPreserved, semanticObjectsPreserved: report.web.semanticObjectsPreserved, zeroUnknownDrift: report.classification.zeroUnknownDrift }, null, 2))
