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

type OfflineReport = {
  schemaVersion: 1
  status: 'pass' | 'failed'
  browserId: 'chrome'
  crossOriginIsolated: boolean
  serviceWorker?: { registered: boolean; controlled: boolean; shellCached: boolean; staleCacheRemoved: boolean; offlineFallback: boolean; cacheNames: string[] }
  persistence?: { mode: string; bytes: number; roundTrip: boolean; released: boolean }
  opfs?: { markerSuite: string; 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 reloadKey = 'bitbybit-rel01-offline-reload'

const run = async (): Promise<OfflineReport> => {
  const report: OfflineReport = { schemaVersion: 1, status: 'failed', browserId: 'chrome', crossOriginIsolated: globalThis.crossOriginIsolated === true }
  const facade = createMockFacade()
  try {
    if (!report.crossOriginIsolated || !navigator.storage?.getDirectory || !('serviceWorker' in navigator)) throw new Error('REL-01 requires isolated OPFS and Service Worker support.')
    const staleCache = await caches.open('bitbybit-cad-shell-stale-test')
    await staleCache.put('/stale-rel01.txt', new Response('stale'))
    const registration = await navigator.serviceWorker.register('/sw.js', { scope: '/' })
    await registration.update()
    await navigator.serviceWorker.ready
    if (!navigator.serviceWorker.controller) {
      sessionStorage.setItem(reloadKey, '1')
      location.reload()
      return report
    }
    const currentCache = await caches.open('bitbybit-cad-shell-v1')
    const shell = await currentCache.match('/index.html')
    await currentCache.put('/offline-probe.txt', new Response('cached-offline-probe', { headers: { 'content-type': 'text/plain' } }))
    await fetch('/__offline-toggle', { method: 'POST', cache: 'no-store' })
    const offlineResponse = await fetch('/offline-probe.txt', { cache: 'no-store' })
    const offlineFallback = (await offlineResponse.text()) === 'cached-offline-probe'
    const cacheNames = await caches.keys()
    const staleCacheRemoved = !cacheNames.includes('bitbybit-cad-shell-stale-test')
    const payload = new TextEncoder().encode(JSON.stringify({ suite: 'REL-01', offlineFallback, cacheNames }))
    const stored = await facade.project.resource.put(payload, 'application/vnd.bitbybit.rel01+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 directory = await navigator.storage.getDirectory()
    const markerName = 'rel01-offline-marker.json'
    const marker = await directory.getFileHandle(markerName, { create: true })
    const writable = await marker.createWritable()
    await writable.write(JSON.stringify({ suite: 'REL-01' }))
    await writable.close()
    const markerPayload = JSON.parse(await (await marker.getFile()).text()) as { suite: string }
    await directory.removeEntry(markerName)
    let markerRemoved = false
    try { await directory.getFileHandle(markerName) } catch (error) { markerRemoved = error instanceof DOMException && error.name === 'NotFoundError' }
    report.serviceWorker = { registered: Boolean(registration.active), controlled: Boolean(navigator.serviceWorker.controller), shellCached: Boolean(shell), staleCacheRemoved, offlineFallback, cacheNames }
    report.persistence = { mode: facade.project.capabilities().mode, bytes: stored.byteLength, roundTrip, released }
    report.opfs = { markerSuite: markerPayload.suite, markerRemoved }
    report.status = report.serviceWorker.registered && report.serviceWorker.controlled && report.serviceWorker.shellCached && staleCacheRemoved && offlineFallback && report.persistence.mode === 'sqlite-opfs' && roundTrip && released && markerPayload.suite === 'REL-01' && markerRemoved ? 'pass' : 'failed'
    sessionStorage.removeItem(reloadKey)
  } catch (error) { report.error = error instanceof Error ? error.stack || error.message : String(error) } finally {
    facade.geometry.dispose()
    await new Promise((resolve) => setTimeout(resolve, 0))
    const capabilities = facade.geometry.capabilities()
    report.afterRelease = { shapeCount: capabilities.shapeCount, kernelReferenceCount: capabilities.kernelReferenceCount }
    if (capabilities.shapeCount !== 0 || capabilities.kernelReferenceCount !== 0) { report.status = 'failed'; report.error = `${report.error ? `${report.error} ` : ''}Shape ownership gate failed.` }
  }
  return report
}

run().then((report) => { ;(window as Window & { __bitbybitOfflineReport?: OfflineReport }).__bitbybitOfflineReport = 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 {}
