import { createMockFacade } from './facade/mockFacade'
import { createDraftDocument } from './facade/draft'

type DraftReport = {
  schemaVersion: 1
  status: 'pass' | 'failed'
  browserId: 'chrome'
  crossOriginIsolated: boolean
  workingPlane?: { worldPoint: { x: number; y: number; z: number }; snapped: { x: number; y: number } }
  objects?: { total: number; lines: number; wires: number; circles: number; clones: number; arrays: number; layers: number; sourceDependencies: number }
  operations?: { moved: boolean; rotated: boolean; scaled: boolean; offsetLength: number; trimmedLength: number; cloneTranslation: { x: number; y: number }; arrayCount: number }
  persistence?: { mode: string; byteLength: number; hash: string; roundTrip: boolean; released: boolean }
  opfs?: { markerSuite: string; markerObjects: number; markerRemoved: boolean }
  afterRelease?: { shapeCount: number; kernelReferenceCount: number }
  error?: string
}

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<DraftReport> => {
  const facade = createMockFacade()
  const report: DraftReport = { schemaVersion: 1, status: 'failed', browserId: 'chrome', crossOriginIsolated: globalThis.crossOriginIsolated === true }
  try {
    if (!report.crossOriginIsolated || !navigator.storage?.getDirectory) throw new Error('Chrome Draft evidence requires isolated OPFS.')
    await facade.project.list()
    const draft = createDraftDocument('draft', 'Draft layout')
    draft.setWorkingPlane({ origin: { x: 10, y: 20, z: 30 }, xAxis: { x: 0, y: 1, z: 0 }, yAxis: { x: 0, y: 0, z: 1 } })
    draft.setGrid(0.5)
    const snapped = draft.snap({ x: 1.24, y: 2.26 })
    const worldPoint = draft.mapToWorld({ x: 2, y: 3 })
    draft.addLayer({ id: 'construction', label: 'Construction', visible: true, color: '#007f86' })
    draft.createLine('line', { x: 0, y: 0 }, { x: 4, y: 0 })
    draft.createWire('wire', [{ x: 0, y: 0 }, { x: 2, y: 0 }, { x: 2, y: 2 }], false, 'construction')
    draft.createCircle('circle', { x: 1, y: 1 }, 2)
    const moved = draft.move('line', { x: 1, y: 2 })
    const rotated = draft.rotate('line', 90, { x: 1, y: 2 })
    const scaled = draft.scale('line', 2, { x: 1, y: 2 })
    const offset = draft.offsetLine('line', 1, 'offset')
    const trimmed = draft.trimLine('line', 0.25, 0.75)
    const clone = draft.clone('line', 'clone', { x: 10, y: 0 })
    const array = draft.array('line', { columns: 2, rows: 2, columnSpacing: 5, rowSpacing: 7, idPrefix: 'array' })
    draft.assignLayer('clone', 'construction')
    const snapshot = draft.snapshot()
    const payload = new TextEncoder().encode(JSON.stringify(snapshot))
    const stored = await facade.project.resource.put(payload, 'application/vnd.bitbybit.draft+json')
    const loaded = await facade.project.resource.get(stored.hash)
    const roundTrip = loaded !== null && await sha256(loaded) === await sha256(payload)
    await facade.project.resource.release(stored.hash)
    const released = await facade.project.resource.get(stored.hash) === null
    const sourceDependencies = snapshot.objects.filter((object) => object.kind === 'clone' && object.sourceId === 'line').length
    const counts = { total: snapshot.objects.length, lines: snapshot.objects.filter((object) => object.kind === 'line').length, wires: snapshot.objects.filter((object) => object.kind === 'wire').length, circles: snapshot.objects.filter((object) => object.kind === 'circle').length, clones: snapshot.objects.filter((object) => object.kind === 'clone').length, arrays: snapshot.objects.filter((object) => object.kind === 'clone' && object.id.startsWith('array-')).length, layers: snapshot.layers.length, sourceDependencies }
    const directory = await navigator.storage.getDirectory()
    const markerName = 'draft-chrome-marker.json'
    const marker = await directory.getFileHandle(markerName, { create: true })
    const writable = await marker.createWritable()
    await writable.write(JSON.stringify({ suite: 'DRAFT-OPS', objects: snapshot.objects.length }))
    await writable.close()
    const markerPayload = JSON.parse(await (await marker.getFile()).text()) as { suite: string; objects: number }
    await directory.removeEntry(markerName)
    let markerRemoved = false
    try { await directory.getFileHandle(markerName) } catch (error) { markerRemoved = error instanceof DOMException && error.name === 'NotFoundError' }
    report.workingPlane = { worldPoint, snapped }
    report.objects = counts
    report.operations = { moved: moved.kind === 'line' && moved.start.x === 1 && moved.start.y === 2, rotated: rotated.kind === 'line' && Math.round(rotated.end.y - rotated.start.y) === 4, scaled: scaled.kind === 'line' && Math.round(Math.hypot(scaled.end.x - scaled.start.x, scaled.end.y - scaled.start.y)) === 8, offsetLength: Math.hypot(offset.end.x - offset.start.x, offset.end.y - offset.start.y), trimmedLength: Math.hypot(trimmed.end.x - trimmed.start.x, trimmed.end.y - trimmed.start.y), cloneTranslation: clone.translation, arrayCount: array.length }
    report.persistence = { mode: facade.project.capabilities().mode, byteLength: stored.byteLength, hash: stored.hash, roundTrip, released }
    report.opfs = { markerSuite: markerPayload.suite, markerObjects: markerPayload.objects, markerRemoved }
    report.status = report.workingPlane.worldPoint.x === 10 && report.workingPlane.worldPoint.y === 22 && report.workingPlane.worldPoint.z === 33 && JSON.stringify(report.workingPlane.snapped) === JSON.stringify({ x: 1, y: 2.5 })
      && counts.total === 9 && counts.lines === 2 && counts.wires === 1 && counts.circles === 1 && counts.clones === 5 && counts.arrays === 4 && counts.layers === 2 && counts.sourceDependencies === 5
      && report.operations.moved && report.operations.rotated && report.operations.scaled && report.operations.offsetLength === 8 && report.operations.trimmedLength === 4 && report.operations.cloneTranslation.x === 10 && report.operations.arrayCount === 4
      && report.persistence.mode === 'sqlite-opfs' && report.persistence.roundTrip && report.persistence.released && report.opfs.markerSuite === 'DRAFT-OPS' && report.opfs.markerObjects === 9 && 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 & { __bitbybitDraftReport?: DraftReport }).__bitbybitDraftReport = 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 {}
