import sqlite3InitModule, { type Database } from '@sqlite.org/sqlite-wasm'
import { PROJECT_SCHEMA_MIGRATIONS } from './projectSchema'

type SeedRequest = { operation: 'seed'; databasePath: string; documentId: string; resourceHash: string; resourceBytes: ArrayBuffer } | { operation: 'inspect'; databasePath: string }
type SeedResponse = { ok: true; schemaVersion: 1; documentId?: string; resourceHash?: string; appliedVersions?: number[] } | { ok: false; error: string }
const scope = globalThis as unknown as { onmessage: ((event: MessageEvent<SeedRequest>) => void) | null; postMessage(message: SeedResponse): void }

scope.onmessage = (event) => {
  void (async () => {
    let database: Database | undefined
    try {
      const request = event.data
      if (!/^\/[A-Za-z0-9._-]+\.sqlite3$/.test(request.databasePath)) throw new Error('Legacy seed database path is invalid.')
      const sqlite3 = await sqlite3InitModule()
      database = new sqlite3.oo1.OpfsDb(request.databasePath)
      if (request.operation === 'inspect') {
        const rows = database.exec({ sql: 'SELECT version FROM schema_migrations ORDER BY version', rowMode: 'object', returnValue: 'resultRows' }) as Array<Record<string, number>>
        scope.postMessage({ ok: true, schemaVersion: 1, appliedVersions: rows.map((row) => Number(row.version)) })
        return
      }
      database.exec(PROJECT_SCHEMA_MIGRATIONS[0].sql)
      const now = Date.now()
      database.exec({ sql: 'INSERT INTO schema_migrations(version, applied_at) VALUES(1, ?)', bind: [now] })
      database.exec({ sql: 'INSERT INTO projects(id, name, schema_version, created_at, updated_at) VALUES(?, ?, 1, ?, ?)', bind: [request.documentId, 'Legacy OPFS project', now, now] })
      database.exec({ sql: 'INSERT INTO documents(id, project_id, label, version, dirty, read_only, units) VALUES(?, ?, ?, 3, 1, 0, ?)', bind: [request.documentId, request.documentId, 'Legacy OPFS project', 'mm'] })
      database.exec({ sql: 'INSERT INTO objects(id, document_id, parent_id, label, object_type, state, detail, children_json, ordinal) VALUES(?, ?, NULL, ?, ?, ?, ?, ?, 0)', bind: ['legacy-root', request.documentId, 'Legacy root', 'PartDesign::Feature', 'valid', 'seeded from schema v1', '[]'] })
      database.exec({ sql: 'INSERT INTO object_properties(document_id, object_id, name, value_json, property_type, updated_at) VALUES(?, ?, ?, ?, ?, ?)', bind: [request.documentId, 'legacy-root', 'Label', JSON.stringify({ name: 'Label', label: 'Label', type: 'App::PropertyString', value: 'Legacy root', recompute: false }), 'App::PropertyString', now] })
      database.exec({ sql: 'INSERT INTO resources(hash, path, byte_length, media_type, ref_count, created_at, updated_at) VALUES(?, ?, ?, ?, 1, ?, ?)', bind: [request.resourceHash, `bitbybit-assets/${request.resourceHash}`, request.resourceBytes.byteLength, 'application/octet-stream', now, now] })
      const root = await navigator.storage.getDirectory()
      const assets = await root.getDirectoryHandle('bitbybit-assets', { create: true })
      const handle = await assets.getFileHandle(request.resourceHash, { create: true })
      const writable = await handle.createWritable()
      await writable.write(request.resourceBytes)
      await writable.close()
      scope.postMessage({ ok: true, schemaVersion: 1, documentId: request.documentId, resourceHash: request.resourceHash })
    } catch (error) {
      scope.postMessage({ ok: false, error: error instanceof Error ? `${error.name}: ${error.message}` : String(error) })
    } finally {
      database?.close()
    }
  })()
}
