import { createMockFacade } from './facade/mockFacade'
import { createTechDrawPage } from './facade/techDraw'
import type { TopoRefValue } from './facade/types'

type TechDrawReport = { schemaVersion: 1; status: 'pass' | 'failed'; browserId: 'chrome'; crossOriginIsolated: boolean; page?: { views: number; sections: number; dimensions: number; annotations: number; tolerances: number; updatedDimension: number; unresolvedRefs: string[]; unresolvedTolerances: string[] }; svg?: { bytes: number; sha256: string; deterministic: boolean; lines: number; accessible: boolean }; pdf?: { bytes: number; sha256: string; deterministic: boolean; validHeader: boolean; validXref: boolean }; resources?: Array<{ mediaType: string; hash: string; byteLength: number; roundTrip: boolean; released: boolean }>; opfs?: { markerSuite: string; markerViews: number; markerRemoved: boolean }; afterRelease?: { shapeCount: number; kernelReferenceCount: number }; error?: string }
const ref = (id: string, version: number): TopoRefValue => ({ schemaVersion: 1, objectId: 'box', kind: 'vertex', persistentId: id, topologyVersion: version, generation: version, status: 'stable', signature: id })
const fixture = (revision: number, length = 4, includeThird = true) => ({ id: 'box', revision, points: [{ id: 'a', ref: ref('Vertex1', revision), point: { x: 0, y: 0, z: 0 } }, { id: 'b', ref: ref('Vertex2', revision), point: { x: length, y: 0, z: 0 } }, ...(includeThird ? [{ id: 'c', ref: ref('Vertex3', revision), point: { x: length, y: 3, z: 0 } }] : [])], edges: includeThird ? [{ id: 'edge', start: 'a', end: 'b' }, { id: 'edge2', start: 'b', end: 'c' }] : [{ id: 'edge', start: 'a', end: 'b' }] })
const sha256 = async (bytes: Uint8Array) => [...new Uint8Array(await crypto.subtle.digest('SHA-256', Uint8Array.from(bytes).buffer))].map((value) => value.toString(16).padStart(2, '0')).join('')

const run = async (): Promise<TechDrawReport> => {
  const facade = createMockFacade()
  const report: TechDrawReport = { schemaVersion: 1, status: 'failed', browserId: 'chrome', crossOriginIsolated: globalThis.crossOriginIsolated === true }
  try {
    if (!report.crossOriginIsolated || !navigator.storage?.getDirectory) throw new Error('Chrome TechDraw evidence requires isolated OPFS.')
    await facade.project.list()
    const page = createTechDrawPage('page', 'Box drawing')
    page.addSource(fixture(1))
    page.addView({ id: 'front', sourceId: 'box', direction: { x: 0, y: 0, z: 1 }, position: { x: 80, y: 80 }, scale: 4 })
    page.addView({ id: 'section', sourceId: 'box', kind: 'section', direction: { x: 0, y: 0, z: 1 }, position: { x: 180, y: 80 }, scale: 4, section: { normal: { x: 1, y: 0, z: 0 }, offset: 2 } })
    page.addDimension({ id: 'length', sourceId: 'box', first: ref('Vertex1', 1), second: ref('Vertex2', 1), label: 'Length' })
    page.addAnnotation({ id: 'note', text: 'Box / Front', position: { x: 20, y: 20 }, style: 'callout' })
    page.addGeometricTolerance({ id: 'flatness', sourceId: 'box', reference: ref('Vertex3', 1), characteristic: 'flatness', value: 0.05, datum: 'A' })
    page.updateSource(fixture(2, 6))
    const afterUpdate = page.snapshot()
    page.updateSource(fixture(3, 6, false))
    const afterDelete = page.snapshot()
    const svg = page.exportSvg()
    const secondSvg = page.exportSvg()
    const svgBytes = new TextEncoder().encode(svg)
    const pdfBytes = page.exportPdf()
    const secondPdf = page.exportPdf()
    const pdfText = new TextDecoder().decode(pdfBytes)
    const resources: TechDrawReport['resources'] = []
    for (const [bytes, mediaType] of [[svgBytes, 'image/svg+xml'], [pdfBytes, 'application/pdf'], [new TextEncoder().encode(JSON.stringify(afterDelete)), 'application/vnd.bitbybit.techdraw+json']] as const) {
      const stored = await facade.project.resource.put(bytes, mediaType)
      const loaded = await facade.project.resource.get(stored.hash)
      const roundTrip = loaded !== null && await sha256(loaded) === await sha256(bytes)
      await facade.project.resource.release(stored.hash)
      const released = await facade.project.resource.get(stored.hash) === null
      resources.push({ mediaType, hash: stored.hash, byteLength: stored.byteLength, roundTrip, released })
    }
    const directory = await navigator.storage.getDirectory(); const markerName = 'techdraw-chrome-marker.json'; const marker = await directory.getFileHandle(markerName, { create: true }); const writable = await marker.createWritable(); await writable.write(JSON.stringify({ suite: 'TD-ALL', views: afterDelete.views.length })); await writable.close(); const markerPayload = JSON.parse(await (await marker.getFile()).text()) as { suite: string; views: number }; await directory.removeEntry(markerName); let markerRemoved = false; try { await directory.getFileHandle(markerName) } catch (error) { markerRemoved = error instanceof DOMException && error.name === 'NotFoundError' }
    const unresolvedRefs = [...new Set(afterDelete.views.flatMap((view) => view.unresolved))].sort()
    const unresolvedTolerances = afterDelete.tolerances.filter((tolerance) => tolerance.status === 'unresolved').map((tolerance) => tolerance.id).sort()
    report.page = { views: afterDelete.views.length, sections: afterDelete.views.filter((view) => view.kind === 'section').length, dimensions: afterDelete.dimensions.length, annotations: afterDelete.annotations.length, tolerances: afterDelete.tolerances.length, updatedDimension: afterUpdate.dimensions[0].value ?? Number.NaN, unresolvedRefs, unresolvedTolerances }
    report.svg = { bytes: svgBytes.byteLength, sha256: await sha256(svgBytes), deterministic: svg === secondSvg, lines: (svg.match(/<line /g) ?? []).length, accessible: svg.includes('role="img"') && svg.includes('aria-label="Box drawing"') }
    report.pdf = { bytes: pdfBytes.byteLength, sha256: await sha256(pdfBytes), deterministic: await sha256(pdfBytes) === await sha256(secondPdf), validHeader: pdfText.startsWith('%PDF-1.4'), validXref: /xref[\s\S]+startxref[\s\S]+%%EOF\n$/.test(pdfText) }
    report.resources = resources
    report.opfs = { markerSuite: markerPayload.suite, markerViews: markerPayload.views, markerRemoved }
    report.status = report.page.views === 2 && report.page.sections === 1 && report.page.dimensions === 1 && report.page.annotations === 1 && report.page.tolerances === 1 && report.page.updatedDimension === 6 && JSON.stringify(report.page.unresolvedRefs) === JSON.stringify(['Vertex3']) && JSON.stringify(report.page.unresolvedTolerances) === JSON.stringify(['flatness']) && report.svg.bytes > 0 && report.svg.deterministic && report.svg.lines === 2 && report.svg.accessible && report.pdf.bytes > 0 && report.pdf.deterministic && report.pdf.validHeader && report.pdf.validXref && resources.every((resource) => resource.roundTrip && resource.released) && report.opfs.markerSuite === 'TD-ALL' && report.opfs.markerViews === 2 && report.opfs.markerRemoved ? 'pass' : 'failed'
  } catch (error) { report.error = error instanceof Error ? error.stack || error.message : String(error) }
  finally { facade.geometry.dispose(); await new Promise((resolve) => setTimeout(resolve, 0)); report.afterRelease = { shapeCount: facade.geometry.capabilities().shapeCount, kernelReferenceCount: facade.geometry.capabilities().kernelReferenceCount }; if (report.afterRelease.shapeCount !== 0 || report.afterRelease.kernelReferenceCount !== 0) { report.status = 'failed'; report.error = `${report.error ? `${report.error} ` : ''}Shape ownership gate failed.` } }
  return report
}

run().then((report) => { ;(window as Window & { __bitbybitTechDrawReport?: TechDrawReport }).__bitbybitTechDrawReport = report; document.documentElement.dataset.status = report.status; document.querySelector('#result')!.textContent = JSON.stringify(report, null, 2) }).catch((error) => { document.documentElement.dataset.status = 'failed'; document.querySelector('#result')!.textContent = error instanceof Error ? error.stack || error.message : String(error) })
export {}
