import { once } from 'node:events'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import pg from 'pg'
import jwt from 'jsonwebtoken'
import type { CaseState } from '../src/types.js'
import { importMysteryTemplate } from '../scripts/importMysteryTemplate.js'
import { runMigrations } from './migrations.js'

const { Client } = pg
const baseDatabaseUrl = process.env.TEST_DATABASE_URL
if (!baseDatabaseUrl) throw new Error('TEST_DATABASE_URL is required for the browser harness')

const databaseName = `osint_e2e_${process.pid}_${Date.now()}`
const adminUrl = new URL(baseDatabaseUrl)
adminUrl.pathname = '/postgres'
const adminClient = new Client({ connectionString: adminUrl.toString() })
await adminClient.connect()
await adminClient.query(`CREATE DATABASE "${databaseName}"`)

const testUrl = new URL(baseDatabaseUrl)
testUrl.pathname = `/${databaseName}`
const databaseUrl = testUrl.toString()
const migrationsDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'migrations')
await runMigrations(databaseUrl, migrationsDir, () => undefined)

const port = Number(process.env.E2E_PORT || 18788)
process.env.DATABASE_URL = databaseUrl
process.env.LEVEL_EDITING_ENABLED = 'true'
process.env.JWT_SECRET = 'osint-e2e-jwt-secret'
process.env.PORT = String(port)
process.env.OSINT_MANAGED_SERVER = 'true'
process.env.ASSET_STORAGE_DRIVER = 'memory'
process.env.OCR_LANGUAGES = 'eng'
const { server, pool } = await import('./index.js')
if (!server.listening) await once(server, 'listening')
const baseUrl = `http://127.0.0.1:${port}`
const adminToken = jwt.sign({ sub: 'e2e-admin', role: 'admin' }, process.env.JWT_SECRET)
const adminHeaders = { 'content-type': 'application/json', authorization: `Bearer ${adminToken}` }
const documentId = '22222222-2222-4222-8222-222222222222'
const folderId = '11111111-1111-4111-8111-111111111111'

const created = await fetch(`${baseUrl}/api/levels`, {
  method: 'POST',
  headers: adminHeaders,
  body: JSON.stringify({ id: 'e2e-level', title: 'Browser Safety Test', subtitle: 'Disposable test level' }),
})
if (!created.ok) throw new Error(`Could not create browser test level: ${created.status}`)
const state = await created.json() as CaseState
state.brief = { body: 'Classify the named people and organizations in this investigation.', concepts: [
  { id: '44444444-4444-4444-8444-444444444444', label: 'Ada Lovelace', context: 'Named as the correspondent.', expectedPartyKind: 'person' },
  { id: '55555555-5555-4555-8555-555555555555', label: 'Difference Engine Bureau', context: 'Issued the archive notice.', expectedPartyKind: 'organization' },
] }
state.exhibits = [{
  id: documentId, type: 'document', title: 'Dated source image', publishedAt: '2021-04-17T12:00:00.000Z',
  body: [], regions: [], fileType: 'image', captureKind:'scene',metadata: {}, x: 980, y: 360, width: 244, height: 200, rotation: 0, zIndex: 2, hidden: false,
}, {
  id: folderId, type: 'folder', title: 'BROWSER TEST FOLDER', content: 'Disposable evidence',
  x: 600, y: 360, width: 260, height: 166, rotation: 0, zIndex: 1, hidden: false, isOpen: false,
}]
state.relations = [{
  id: `contains:${folderId}:${documentId}`, fromExhibitId: folderId, toExhibitId: documentId, type: 'contains', sortOrder: 0,
}]
state.connections = []
state.viewport = { x: 0, y: 28, zoom: 0.7 }
const saved = await fetch(`${baseUrl}/api/levels/${state.id}?edit=1`, {
  method: 'PUT',
  headers: adminHeaders,
  body: JSON.stringify(state),
})
if (!saved.ok) throw new Error(`Could not seed browser test level: ${saved.status}`)

const glassHarbor = await importMysteryTemplate(path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'mysteries', 'glass-harbor', 'mystery.json'), baseUrl, adminToken)
const revealAuction = await fetch(`${baseUrl}/api/levels/${glassHarbor.playableLevel.id}/flags/lead.auction_catalogue`, {
  method: 'PUT', headers: adminHeaders,
})
if (!revealAuction.ok) throw new Error(`Could not reveal the acceptance-test auction catalogue: ${revealAuction.status}`)
await importMysteryTemplate(path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'mysteries', 'barricelli-scene-7', 'mystery.json'), baseUrl, adminToken)

let shuttingDown = false
async function shutdown(exitCode: number) {
  if (shuttingDown) return
  shuttingDown = true
  if (server.listening) await new Promise<void>((resolve, reject) => server.close(error => error ? reject(error) : resolve()))
  await pool.end()
  await adminClient.query(`DROP DATABASE IF EXISTS "${databaseName}"`)
  await adminClient.end()
  process.exit(exitCode)
}

process.on('SIGTERM', () => void shutdown(0))
process.on('SIGINT', () => void shutdown(0))
process.on('uncaughtException', error => { console.error(error); void shutdown(1) })
process.on('unhandledRejection', error => { console.error(error); void shutdown(1) })
console.log(`Browser safety harness ready on ${baseUrl}`)
