import { createServer } from 'node:http'
import { existsSync } from 'node:fs'
import { writeFile } from 'node:fs/promises'
import { resolve } from 'node:path'
import { spawn } from 'node:child_process'
import { createChromeProfile, removeChromeProfile } from './chrome-profile.mjs'

const root = resolve(new URL('..', import.meta.url).pathname)
const reportPath = resolve(root, 'config/chrome-property-direction-verification.json')
const waitForPort = (child) => new Promise((resolvePort, reject) => {
  let output = ''
  const timer = setTimeout(() => reject(new Error(`Vite did not announce a port: ${output.slice(-2000)}`)), 30_000)
  const onData = (chunk) => { output += String(chunk); const match = output.match(/http:\/\/127\.0\.0\.1:(\d+)/); if (match) { clearTimeout(timer); resolvePort(Number(match[1])) } }
  child.stdout.on('data', onData)
  child.stderr.on('data', onData)
})

const vite = spawn('./nodew', ['node_modules/vite/bin/vite.js', '--host', '127.0.0.1'], { cwd: root, stdio: ['ignore', 'pipe', 'pipe'] })
let vitePort
try { vitePort = await waitForPort(vite) } catch (error) { vite.kill('SIGTERM'); throw error }
let resolveReport
const reportPromise = new Promise((resolveValue) => { resolveReport = resolveValue })
const server = createServer(async (request, response) => {
  response.setHeader('Cross-Origin-Opener-Policy', 'same-origin')
  response.setHeader('Cross-Origin-Embedder-Policy', 'require-corp')
  response.setHeader('Cross-Origin-Resource-Policy', 'same-origin')
  if (request.method === 'POST' && request.url === '/__chrome-property-direction-report') {
    let body = ''
    request.setEncoding('utf8')
    request.on('data', (chunk) => { body += String(chunk) })
    request.on('end', async () => { const report = JSON.parse(body); await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`); resolveReport(report); response.writeHead(204); response.end() })
    return
  }
  try {
    const upstream = await fetch(`http://127.0.0.1:${vitePort}${request.url}`, { headers: { ...request.headers } })
    response.writeHead(upstream.status, Object.fromEntries(upstream.headers.entries()))
    response.end(Buffer.from(await upstream.arrayBuffer()))
  } catch (error) { response.writeHead(502); response.end(String(error)) }
})
await new Promise((resolveServer) => server.listen(0, '127.0.0.1', resolveServer))
const port = server.address().port
const executable = process.env.CHROME_BIN || '/home/mes123456/.local/bin/google-chrome'
if (!existsSync(executable)) throw new Error(`Chrome executable is missing: ${executable}`)
const chromeProfile = await createChromeProfile('property-direction')
const chrome = spawn(executable, ['--headless=new', '--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage', '--noerrdialogs', '--no-first-run', `--user-data-dir=${chromeProfile}`, `http://127.0.0.1:${port}/chrome-property-direction-harness.html`], { cwd: root, stdio: ['ignore', 'ignore', 'pipe'] })
let chromeStderr = ''
chrome.stderr.on('data', (chunk) => { chromeStderr += String(chunk) })
let timeoutId
const timeoutReport = new Promise((resolveTimeout) => { timeoutId = setTimeout(() => resolveTimeout({ status: 'timeout', browserId: 'chrome' }), 120_000) })
const report = await Promise.race([reportPromise, timeoutReport])
clearTimeout(timeoutId)
chrome.kill('SIGTERM')
vite.kill('SIGTERM')
server.closeAllConnections?.()
server.close()
await removeChromeProfile(chromeProfile)
console.log(JSON.stringify(report, null, 2))
if (report.status !== 'pass') {
  if (chromeStderr) console.error(chromeStderr.slice(-3000))
  process.exit(1)
}
