import test from 'node:test'
import assert from 'node:assert/strict'
import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
import { join, resolve } from 'node:path'
import { tmpdir } from 'node:os'
import { inspectWasmStaticArchive } from '../scripts/freecad-naming-sdk-lib.mjs'

const root = resolve(new URL('..', import.meta.url).pathname)

const arArchive = (member, bytes) => {
  const field = (value, length) => String(value).padEnd(length, ' ')
  const header = `${field(`${member}/`, 16)}${field(0, 12)}${field(0, 6)}${field(0, 6)}${field('100644', 8)}${field(bytes.length, 10)}` + '`\n'
  return Buffer.concat([Buffer.from('!<arch>\n'), Buffer.from(header), bytes, ...(bytes.length % 2 ? [Buffer.from('\n')] : [])])
}

test('Qt wasm Core build pins the released QtBase source and project Emscripten baseline', async () => {
  const source = await readFile(resolve(root, 'scripts/build-qt6-wasm-core.sh'), 'utf8')
  const freecadQt = await readFile(resolve(root, 'scripts/build-qt6-freecad-wasm.sh'), 'utf8')
  assert.match(source, /QT_VERSION="6\.8\.2"/)
  assert.match(source, /012043ce6d411e6e8a91fdc4e05e6bedcfa10fcb1347d3c33908f7fdd10dfe05/)
  assert.match(source, /Emscripten 3\.1\.69/)
  assert.match(source, /mirrors\.ustc\.edu\.cn/)
  assert.match(source, /WEB_FREECAD_OFFLINE/)
  assert.match(source, /cmake --install "\$\{QT_BUILD_DIR\}\/src\/corelib"/)
  assert.doesNotMatch(source, /cmake --install[^\n]+\|\| true/)
  assert.match(freecadQt, /Core Concurrent Network Xml/)
  assert.match(freecadQt, /feature-thread/)
  assert.match(freecadQt, /mkspecs\/wasm-emscripten/)
  assert.match(freecadQt, /inspectWasmStaticArchive/)
})

test('FreeCAD source probe pins the exact private source inputs and does not export the production ABI', async () => {
  const build = await readFile(resolve(root, 'scripts/build-freecad-naming-source-probe.sh'), 'utf8')
  const smoke = await readFile(resolve(root, 'native/freecad-naming-probe/smoke-test.mjs'), 'utf8')
  const candidate = await readFile(resolve(root, 'native/freecad-naming-probe/abi-candidate-smoke.ts'), 'utf8')
  assert.match(build, /0108fd4b4850cc46e625b60e53cea7a7bbe69f8d/)
  assert.match(build, /73e0e60a9d6ee06851252e2071ebdd58698f8f99733903232529b3a194164435/)
  assert.match(build, /90173aba5f331ac9453589833f7e5fc63c5c80a35f1600dbc71211606b1c9dbc/)
  assert.match(build, /fd32f35c9c2a0c21a60fa634ec37ec594d6f331924c5bba7fdbbcb351c3b612c/)
  assert.match(build, /8f02d27a8b672e9a56764f85e394265b4fcf023aba097f040b03dcb38bc393d2/)
  assert.match(build, /StringHasher\.cpp/)
  assert.match(build, /Base\/Handle\.cpp/)
  assert.match(build, /f5448d9de693e319460d5e3ef52c63a54e0948963e4b92786aac38c77bdcd7a5/)
  assert.match(build, /fc3223857ca6d2990d2b48f437f75841cdf23e1e79fa18ef18296f40acd3cdc3/)
  assert.match(build, /e1ceaedb624688ddffa6a834c1b32539e8ba5bbdc0ec31401ea087e6a9c3eb52/)
  assert.match(build, /MappedElement\.cpp/)
  assert.match(build, /ElementNamingUtils\.cpp/)
  assert.match(build, /ElementMap\.cpp/)
  assert.match(build, /libFreeCADPrivateNamingProbe\.a/)
  assert.match(build, /emar rcs/)
  assert.match(build, /git -C "\$\{FREECAD_SOURCE_DIR\}" diff --quiet/)
  assert.doesNotMatch(build, /public\/native\/freecad-naming-probe/)
  for (const callback of ['freecadNamingAbiVersion', 'freecadNamingCapabilitiesJson', 'freecadNamingEvidenceJson']) {
    assert.match(smoke, new RegExp(callback))
  }
  assert.match(smoke, /productionWorkerLinked: false/)
  assert.match(smoke, /freecadPrivateStringHasherSourceProbe/)
  assert.match(smoke, /freecadPrivateElementMapSourceProbe/)
  assert.match(smoke, /archive\.memberCount !== 7/)
  assert.match(smoke, /productionEligible: false/)
  assert.match(candidate, /captureFreeCadPrivateNamingEvidence/)
  assert.match(candidate, /parseElementMap2/)
  assert.match(candidate, /productionCallbacksExported: false/)
  assert.match(candidate, /productionWorkerLinked: false/)
})

test('private naming boundary checker cross-validates all authoritative status files', async () => {
  const source = await readFile(resolve(root, 'scripts/check-freecad-private-naming-boundary.mjs'), 'utf8')
  for (const path of [
    'config/freecad-sketcher-partdesign-abi-contract.json',
    'config/compatibility-matrix.json',
    'config/freecad-web-exact-parity-plan.json',
    'config/freecad-private-naming-source-readiness.json',
    'config/freecad-naming-sdk-plan.json',
  ]) assert.match(source, new RegExp(path.replaceAll('.', '\\.')))
  assert.match(source, /shippedWorkerImplementation !== 'freecad-linked'/)
  assert.match(source, /task\.status !== 'completed'/)
  assert.match(source, /systemExactEvaluation\?\.exact !== false/)
  assert.match(source, /production\?\.workerLinked !== true/)
  assert.match(source, /candidateAbi\?\.scope !== 'isolated-non-production'/)
  assert.match(source, /callback\.startsWith\('freecadNamingCandidate'\)/)
  assert.match(source, /productionLinkedComponents/)
  assert.match(source, /sdkPlan\.productionPublication !== false/)
})

test('SDK readiness verifies the complete candidate wasm closure and keeps it pre-production', async () => {
  const plan = JSON.parse(await readFile(resolve(root, 'config/freecad-naming-sdk-plan.json'), 'utf8'))
  const readiness = await readFile(resolve(root, 'scripts/check-freecad-naming-sdk-readiness.mjs'), 'utf8')
  const sdkBuildPlan = await readFile(resolve(root, 'config/freecad-wasm-sdk-build-plan.json'), 'utf8')
  const sdkBootstrap = await readFile(resolve(root, 'config/freecad-wasm-sdk-bootstrap.cmake'), 'utf8')
  const sdkCompat = await readFile(resolve(root, 'config/freecad-wasm-sdk-compat.h'), 'utf8')
  const sdkExecinfo = await readFile(resolve(root, 'config/wasm-compat/execinfo.h'), 'utf8')
  const sdkToolchain = await readFile(resolve(root, 'config/emscripten-freecad-candidate-toolchain.cmake'), 'utf8')
  const sdkConfigure = await readFile(resolve(root, 'scripts/configure-freecad-naming-sdk-candidate.mjs'), 'utf8')
  const sdkBuild = await readFile(resolve(root, 'scripts/build-freecad-naming-sdk-candidate.sh'), 'utf8')
  const sdkOverlay = await readFile(resolve(root, 'scripts/prepare-freecad-occt8-overlay.sh'), 'utf8')
  const sdkCheck = await readFile(resolve(root, 'scripts/check-freecad-naming-sdk.mjs'), 'utf8')
  const sdkManifest = await readFile(resolve(root, 'scripts/generate-freecad-naming-sdk-manifest.mjs'), 'utf8')
  const bridgeBuild = await readFile(resolve(root, 'scripts/build-freecad-naming-bridge-candidate.sh'), 'utf8')
  const bridgeSmoke = await readFile(resolve(root, 'native/freecad-naming-bridge/smoke-test.ts'), 'utf8')
  const bridgeCheck = await readFile(resolve(root, 'scripts/check-freecad-naming-bridge-candidate.mjs'), 'utf8')
  const workerBuild = await readFile(resolve(root, 'native/occt-history/build.sh'), 'utf8')
  const workerSmoke = await readFile(resolve(root, 'native/occt-history/freecad-naming-candidate-smoke.ts'), 'utf8')
  const chromeRun = await readFile(resolve(root, 'scripts/run-chrome-freecad-naming-worker-candidate.mjs'), 'utf8')
  const chromeCheck = await readFile(resolve(root, 'scripts/check-chrome-freecad-naming-worker-candidate.mjs'), 'utf8')
  assert.equal(plan.productionPublication, false)
  assert.deepEqual(plan.libraries.map(({ name }) => name), ['FreeCADBase', 'FreeCADApp', 'Part', 'QtCore', 'Python'])
  assert.deepEqual(plan.linkDependencies.map(({ name }) => name), ['QtConcurrent', 'QtNetwork', 'QtXml', 'QtBundledPcre2', 'QtBundledZLIB', 'yaml-cpp', 'ICUCommon', 'ICUI18N', 'ICUData', 'XercesC', 'BoostProgramOptions', 'BoostRegex', 'BoostThread', 'BoostDateTime', 'BoostAtomic', 'PythonMpdecimal', 'PythonExpat', 'PythonHaclSha2', 'PythonZlib', 'PythonBzip2', 'PythonSqlite3'])
  assert.equal(plan.compileOptions.cxxStandard, 'c++20')
  assert.equal(plan.compileOptions.pthread, true)
  assert.deepEqual(plan.runtimeAssets.map(({ name }) => name), ['PythonWasmStdlib'])
  assert.match(readiness, /inspectPlannedLibrary/)
  assert.match(readiness, /publishToWorker: false/)
  assert.match(readiness, /inspectPlannedRuntimeAsset/)
  assert.match(sdkCheck, /inspectWasmStaticArchive/)
  assert.match(sdkCheck, /hostAdapterSha256/)
  assert.match(sdkCheck, /forceIncludeSha256/)
  assert.match(sdkCheck, /PythonWasmStdlib/)
  assert.match(sdkManifest, /runtimeAssets/)
  assert.match(sdkManifest, /productionPublication: false/)
  assert.match(sdkBuildPlan, /candidate-only-freecad-wasm-sdk-build/)
  assert.match(sdkBuildPlan, /productionPublication": false/)
  assert.match(sdkBootstrap, /FREECAD_WASM_EMBED_TRANSLATIONS OFF/)
  assert.match(sdkBootstrap, /function\(qt_add_translation output_variable\)/)
  assert.match(sdkBootstrap, /add_compile_definitions\(__linux__=1\)/)
  assert.match(sdkBootstrap, /FREECAD_WASM_OCCT_COMPAT_INCLUDE/)
  assert.match(sdkBootstrap, /TopTools_ListOfShape\.hxx/)
  assert.match(sdkBootstrap, /set\(UNIX FALSE\)/)
  assert.match(sdkToolchain, /Platform\/Emscripten\.cmake/)
  assert.match(sdkToolchain, /set\(UNIX FALSE\)/)
  assert.match(sdkToolchain, /CMAKE_CXX_CREATE_SHARED_LIBRARY/)
  assert.match(sdkBootstrap, /freecad-wasm-sdk-compat\.h/)
  assert.match(sdkCompat, /#include <TopTools_ListOfShape\.hxx>/)
  assert.match(sdkCompat, /#include <TopTools_HSequenceOfShape\.hxx>/)
  assert.match(sdkCompat, /#define systemTimeZone\(\) UTC/)
  assert.doesNotMatch(sdkExecinfo, /backtrace\s*\(/)
  assert.match(sdkConfigure, /Qt6_DIR/)
  assert.match(sdkConfigure, /Python3_INCLUDE_DIRS/)
  assert.match(sdkConfigure, /FREECAD_WASM_OFFLINE_SYSROOT/)
  assert.match(sdkConfigure, /src\/Deprecated\/NCollectionAliases/)
  assert.match(sdkConfigure, /source-occt8/)
  assert.match(sdkOverlay, /migrate_raise_to_throw\.py/)
  assert.match(sdkOverlay, /replace_typedefs\.py/)
  assert.match(sdkOverlay, /collected_typedefs\.json/)
  assert.match(sdkOverlay, /TopTools_ListIteratorOfListOfShape\.hxx\|TopTools_ListOfShape\.hxx/)
  assert.match(sdkOverlay, /removed_iterator_headers/)
  assert.match(sdkOverlay, /e\.DynamicType\(\)->get_type_name\(\)\|e\.ExceptionType\(\)/)
  assert.match(sdkOverlay, /legacy_exception_rtti/)
  assert.match(sdkOverlay, /BRepLProp_CurveTool::FirstParameter\(adapt\)\|adapt\.FirstParameter\(\)/)
  assert.match(sdkOverlay, /legacy_curve_tool/)
  assert.match(sdkOverlay, /Geom2dLProp_CLProps2d\.hxx>\|#include <GeomLProp_CLProps\.hxx>/)
  assert.match(sdkOverlay, /legacy_geom2d_lprop/)
  assert.match(sdkOverlay, /std::vector<TopoShape>\{e1, e2, e3, e4\}/)
  assert.match(sdkOverlay, /ambiguous_shape_mapper_calls/)
  assert.match(sdkOverlay, /Standard_Failure inherits std::exception/)
  assert.match(sdkOverlay, /unreachable_occt_exception_fallbacks/)
  assert.match(sdkOverlay, /worktree add --detach/)
  assert.match(sdkOverlay, /git -C "\$\{FREECAD_SOURCE_DIR\}" diff --quiet/)
  assert.match(sdkConfigure, /FreeCADBase|BUILD_PART/)
  assert.match(sdkConfigure, /freecadNamingEvidenceJson/)
  assert.match(sdkBuild, /cmake --build "\$\{BUILD_DIR\}" --target Part/)
  assert.match(sdkBuild, /libFreeCADBase\.a/)
  assert.match(sdkBuild, /ElementMap\.cpp\.o/)
  assert.match(sdkBuild, /productionManifestGenerated: false/)
  assert.match(sdkBuild, /availability: 'available'/)
  assert.match(bridgeBuild, /libHacl_Hash_SHA2\.a/)
  assert.match(bridgeBuild, /--preload-file/)
  assert.match(bridgeBuild, /FREECAD_NAMING_BRIDGE_REPORT/)
  assert.match(bridgeBuild, /public\/native\/freecad-naming-bridge/)
  assert.match(bridgeSmoke, /freecad-private-naming-isolated-bridge-pass/)
  assert.match(bridgeSmoke, /thirdStage/)
  assert.match(bridgeSmoke, /tamperedHasherRejected/)
  assert.match(bridgeSmoke, /inconsistentTablesRejected/)
  assert.match(bridgeSmoke, /productionWorkerLinked: false/)
  assert.match(bridgeCheck, /thirdStage\?\.stringHasherEntries <= report\.chainedStage\.stringHasherEntries/)
  assert.match(bridgeCheck, /stale artifact evidence/)
  assert.match(workerBuild, /OCCT_HISTORY_PUBLISH/)
  assert.match(workerBuild, /m\.runtimeAssets/)
  assert.match(workerBuild, /m\.compileOptions\.definitions/)
  assert.match(workerBuild, /OCCT_CXX_FLAGS\+=" -pthread"/)
  assert.match(workerSmoke, /booleanHistoryFromStep/)
  assert.match(workerSmoke, /thirdStage/)
  assert.match(workerSmoke, /invalidHistoryRejected: true/)
  assert.match(chromeRun, /crossOriginIsolated/)
  assert.match(chromeRun, /thirdStage/)
  assert.match(chromeRun, /productionWorkerLinked: false/)
  assert.match(chromeCheck, /thirdStage\?\.stringHasherEntries <= report\.chainedStage\.stringHasherEntries/)
  assert.match(chromeCheck, /stale artifact evidence/)
  const fixtureDir = await mkdtemp(join(tmpdir(), 'freecad-naming-sdk-'))
  try {
    const wasmArchive = join(fixtureDir, 'libwasm.a')
    const hostArchive = join(fixtureDir, 'libhost.a')
    await writeFile(wasmArchive, arArchive('wasm.o', Buffer.from([0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00])))
    await writeFile(hostArchive, arArchive('host.o', Buffer.from([0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00])))
    const wasm = await inspectWasmStaticArchive(wasmArchive)
    assert.equal(wasm.target, 'wasm32-emscripten')
    assert.equal(wasm.wasmObjectCount, 1)
    await assert.rejects(inspectWasmStaticArchive(hostArchive), /host ELF object/)
  } finally {
    await rm(fixtureDir, { recursive: true, force: true })
  }
})

test('real wasm and offline smoke lanes rebuild and execute the source prerequisite', async () => {
  const real = await readFile(resolve(root, 'scripts/run-real-verification.mjs'), 'utf8')
  const offline = await readFile(resolve(root, 'scripts/offline-resource-lib.mjs'), 'utf8')
  for (const source of [real, offline]) {
    assert.match(source, /build:freecad-naming-source-probe/)
    assert.match(source, /test:freecad-naming-source-probe/)
    assert.match(source, /check:freecad-naming-sdk-readiness/)
    assert.match(source, /check:freecad-wasm-sdk-build-plan/)
  }
  assert.match(real, /build:qt6-wasm-core/)
  assert.match(real, /probe:freecad-attachment-modes/)
  assert.match(real, /name\.startsWith\('test:chrome-'\)/)
  assert.match(real, /requestedPhase === 'execute' \? chromeExecution : chromeChecks/)
  assert.match(real, /test:freecad-naming-production/)
  assert.match(real, /test:freecad-isomorphic-provenance/)
  assert.match(real, /probe:freecad-native-property-semantics/)
  assert.match(offline, /publish:occt-history/)
  assert.match(offline, /check:freecad-naming-production/)
  assert.match(offline, /check:freecad-isomorphic-provenance/)
  assert.match(offline, /check:freecad-native-property-semantics/)
})
