import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import http from 'node:http';
import net from 'node:net';
import os from 'node:os';
import path from 'node:path';
import { spawn } from 'node:child_process';
import { prepareTestRuntime, serverTestEnv } from './helpers.js';

function reservePort() {
  return new Promise((resolve, reject) => {
    const server = net.createServer();
    server.once('error', reject);
    server.listen(0, '127.0.0.1', () => {
      const address = server.address();
      const port = typeof address === 'object' && address ? address.port : 0;
      server.close((error) => error ? reject(error) : resolve(port));
    });
  });
}

function health(port) {
  return new Promise((resolve) => {
    const req = http.get({ hostname: '127.0.0.1', port, path: '/api/health', timeout: 500 }, (res) => {
      const chunks = [];
      res.on('data', (chunk) => chunks.push(chunk));
      res.on('end', () => {
        try {
          const body = JSON.parse(Buffer.concat(chunks).toString('utf8'));
          resolve(res.statusCode === 200 && body?.service === 'onlycoin-api');
        } catch {
          resolve(false);
        }
      });
    });
    req.once('timeout', () => { req.destroy(); resolve(false); });
    req.once('error', () => resolve(false));
  });
}

async function waitForHealth(port, child) {
  for (let attempt = 0; attempt < 80; attempt += 1) {
    if (child.exitCode != null) return false;
    if (await health(port)) return true;
    await new Promise((resolve) => setTimeout(resolve, 100));
  }
  return false;
}

test('dedicated server entrypoint starts and answers health checks', async (t) => {
  const port = await reservePort();
  const dataDir = fs.mkdtempSync(path.join(os.tmpdir(), 'onlycoin-startup-'));
  const output = [];
  const rootDir = path.resolve(import.meta.dirname, '../..');
  prepareTestRuntime(rootDir, dataDir, { APP_ORIGIN: `http://127.0.0.1:${port}` });
  const child = spawn(process.execPath, ['--no-warnings', 'server/src/main.js'], {
    cwd: rootDir,
    env: serverTestEnv({ dataDir, port, base: `http://127.0.0.1:${port}` }),
    stdio: ['ignore', 'pipe', 'pipe'],
    windowsHide: true
  });
  child.stdout.on('data', (chunk) => output.push(chunk.toString('utf8')));
  child.stderr.on('data', (chunk) => output.push(chunk.toString('utf8')));

  t.after(async () => {
    if (child.exitCode == null) child.kill('SIGTERM');
    await new Promise((resolve) => {
      if (child.exitCode != null) return resolve();
      const timer = setTimeout(() => {
        if (child.exitCode == null) child.kill('SIGKILL');
        resolve();
      }, 3000);
      child.once('exit', () => { clearTimeout(timer); resolve(); });
    });
    fs.rmSync(dataDir, { recursive: true, force: true });
  });

  const ready = await waitForHealth(port, child);
  assert.equal(ready, true, `Server did not become healthy. Output:\n${output.join('')}`);
});
