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

const root = resolve(new URL('..', import.meta.url).pathname)
const sourcePath = resolve(root, '.cache/freecad/reference-desktop.json')
const reportPath = resolve(root, 'config/freecad-property-boollist-inventory.json')
const fail = (message) => { throw new Error(`FreeCAD PropertyBoolList inventory check failed: ${message}`) }
const [sourceContent, reportContent] = await Promise.all([readFile(sourcePath), readFile(reportPath)])
const source = JSON.parse(sourceContent)
const report = JSON.parse(reportContent)
if (report.schemaVersion !== 1 || report.status !== 'pass' || report.propertyType !== 'App::PropertyBoolList' || report.classification !== 'opaque-fcstd-proxy') fail('report boundary is invalid')
if (report.baseline?.freecadVersion !== '1.1.1' || report.baseline?.commit !== '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d') fail('baseline is not locked to FreeCAD 1.1.1')
if (report.source?.path !== '.cache/freecad/reference-desktop.json' || report.source.bytes !== sourceContent.length || report.source.sha256 !== createHash('sha256').update(sourceContent).digest('hex')) fail('source provenance is stale')
if (report.recordCount !== 7 || !Array.isArray(report.records) || report.records.length !== 7) fail('record count is not exactly seven')
const expected = [
  ['App::FeatureTest', 'BoolList', '', [], [false]],
  ['App::FeatureTestException', 'BoolList', '', [], [false]],
  ['App::Link', 'VisibilityList', ' Link', ['Immutable', 'Hidden', 'LockDynamic'], []],
  ['App::LinkGroup', 'VisibilityList', ' Link', ['Immutable', 'Hidden', 'LockDynamic'], []],
  ['App::LinkGroupPython', 'VisibilityList', ' Link', ['Immutable', 'Hidden', 'LockDynamic'], []],
  ['App::LinkPython', 'VisibilityList', ' Link', ['Immutable', 'Hidden', 'LockDynamic'], []],
  ['Surface::GeomFillSurface', 'ReversedList', '', [], [false]],
]
for (const [objectTypeId, propertyName, group, status, defaultValue] of expected) {
  const record = report.records.find((candidate) => candidate.objectTypeId === objectTypeId && candidate.propertyName === propertyName)
  if (!record || record.objectAvailable !== true || record.probeStatus !== 'available' || record.group !== group || JSON.stringify(record.status) !== JSON.stringify(status) || JSON.stringify(record.defaultValue) !== JSON.stringify(defaultValue) || record.valueModel?.kind !== 'boolean-list' || record.valueModel.elementType !== 'bool' || record.valueModel.cardinality !== 'variable' || !Array.isArray(record.dependencies) || record.dependencies.length !== 0 || record.applicability?.requiredObjectTypeId !== record.objectTypeId) fail(`native inventory changed for ${objectTypeId}.${propertyName}`)
}
const nativeMatches = []
for (const objectType of source.runtimeObjects?.types ?? []) for (const property of objectType.properties ?? []) if (property.typeId === 'App::PropertyBoolList') nativeMatches.push({ objectTypeId: objectType.typeId, propertyName: property.name, group: property.group, status: property.status, defaultValue: property.default })
if (nativeMatches.length !== 7) fail('locked runtime oracle no longer contains seven BoolList records')
console.log(JSON.stringify({ status: 'freecad-property-boollist-inventory-pass', propertyType: report.propertyType, recordCount: report.recordCount, writableRecords: report.records.filter(({ valueModel }) => valueModel.writable).length, immutableRecords: report.records.filter(({ valueModel }) => !valueModel.writable).length, classification: report.classification }, null, 2))
