import { spawn } from 'node:child_process';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const port = 3219;
const base = `http://127.0.0.1:${port}`;
const testDb = path.join(ROOT, 'data', 'smoke-orders.sqlite');
for (const suffix of ['', '-shm', '-wal']) try { fs.unlinkSync(testDb + suffix); } catch {}
const child = spawn(process.execPath, ['src/server.js'], {
  cwd: ROOT,
  env: { ...process.env, NODE_ENV: 'test', PORT: String(port), BASE_URL: base, PAYPAL_ENV: 'mock', ALLOW_MOCK_PAYPAL: 'true', DB_PATH: testDb },
  stdio: ['ignore', 'pipe', 'pipe']
});
let output = '';
child.stdout.on('data', (chunk) => { output += chunk; process.stdout.write(chunk); });
child.stderr.on('data', (chunk) => process.stderr.write(chunk));

async function waitForServer() {
  for (let i = 0; i < 60; i += 1) {
    try { const response = await fetch(`${base}/health`); if (response.ok) return; } catch {}
    await new Promise((resolve) => setTimeout(resolve, 150));
  }
  throw new Error(`Server did not start. ${output}`);
}
function assert(condition, message) { if (!condition) throw new Error(message); }

try {
  await waitForServer();
  for (const route of ['/', '/privacy', '/terms', '/refunds', '/success', '/health', '/robots.txt', '/sitemap.xml', '/does-not-exist']) {
    const response = await fetch(`${base}${route}`);
    assert(response.status === 200, `${route} returned ${response.status}`);
  }
  const create = await fetch(`${base}/api/paypal/create-order`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: '{}' }).then((r) => r.json());
  assert(create.ok && create.id, 'Mock create order failed');
  const capture = await fetch(`${base}/api/paypal/capture-order`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ orderID: create.id }) }).then((r) => r.json());
  assert(capture.ok && capture.downloadToken, 'Mock capture/order entitlement failed');
  const claim = await fetch(`${base}/claim/${capture.downloadToken}`);
  assert(claim.status === 200, `Claim route returned ${claim.status}`);
  const download = await fetch(`${base}/download/${capture.downloadToken}`, { method: 'POST' });
  assert(download.status === 200 && download.headers.get('content-type') === 'application/pdf', 'First download failed');
  assert((await download.arrayBuffer()).byteLength > 1_000_000, 'Downloaded PDF is unexpectedly small');
  const second = await fetch(`${base}/download/${capture.downloadToken}`, { method: 'POST' });
  assert(second.status === 410, `Second download should return 410, received ${second.status}`);
  console.log('\nSMOKE TEST PASSED: routes, payment, entitlement, PDF delivery and one-time enforcement.\n');
} finally {
  child.kill('SIGTERM');
  await new Promise((resolve) => setTimeout(resolve, 300));
}
