import { spawn } from 'node:child_process';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';

const projectRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const serverSpecs = [
  { name: 'viewer-2d', args: ['run', 'dev:2d'] },
  { name: 'viewer-3d', args: ['run', 'dev:3d'] },
  {
    name: 'viewer-2d-subpath',
    args: ['--workspace', '@hmwebviewer/viewer-2d-sample', 'run', 'serve:subpath:e2e'],
  },
  {
    name: 'viewer-3d-subpath',
    args: ['--workspace', '@hmwebviewer/viewer-3d', 'run', 'serve:subpath:e2e'],
  },
];
const servers = [];
let stopping = false;

function stopServers() {
  if (stopping) return;
  stopping = true;
  for (const server of servers) {
    if (!server.pid) continue;
    try {
      // npm과 그 아래 Vite process를 같은 process group 단위로 종료합니다.
      process.kill(-server.pid, 'SIGTERM');
    } catch {
      // 이미 종료된 server는 별도 처리하지 않습니다.
    }
  }
}

function startServer({ name, args }) {
  return new Promise((resolveReady, rejectReady) => {
    const child = spawn('npm', args, {
      cwd: projectRoot,
      detached: true,
      env: {
        ...process.env,
        NO_PROXY: '127.0.0.1,localhost',
        no_proxy: '127.0.0.1,localhost',
      },
      stdio: ['ignore', 'pipe', 'pipe'],
    });
    servers.push(child);

    let ready = false;
    const timeout = setTimeout(() => {
      rejectReady(new Error(`${name} server가 90초 안에 준비되지 않았습니다.`));
    }, 90_000);

    const inspect = (chunk) => {
      const output = chunk.toString();
      process.stderr.write(`[${name}] ${output}`);
      if (!ready && output.includes('Local:')) {
        ready = true;
        clearTimeout(timeout);
        resolveReady();
      }
    };
    child.stdout.on('data', inspect);
    child.stderr.on('data', inspect);
    child.once('exit', (code, signal) => {
      clearTimeout(timeout);
      if (!ready) {
        rejectReady(
          new Error(`${name} server가 준비 전에 종료됐습니다. code=${code} signal=${signal}`),
        );
      }
    });
  });
}

process.once('SIGINT', () => {
  stopServers();
  process.exit(130);
});
process.once('SIGTERM', () => {
  stopServers();
  process.exit(143);
});

try {
  await Promise.all(serverSpecs.map(startServer));

  const playwright = spawn(
    resolve(projectRoot, 'node_modules/.bin/playwright'),
    ['test', ...process.argv.slice(2)],
    {
      cwd: projectRoot,
      env: {
        ...process.env,
        E2E_SERVERS_READY: '1',
        NO_PROXY: '127.0.0.1,localhost',
        no_proxy: '127.0.0.1,localhost',
      },
      stdio: 'inherit',
    },
  );
  const exitCode = await new Promise((resolveExit) => {
    playwright.once('exit', (code, signal) => {
      if (signal) resolveExit(1);
      else resolveExit(code ?? 1);
    });
  });
  process.exitCode = exitCode;
} catch (error) {
  console.error(error);
  process.exitCode = 1;
} finally {
  stopServers();
}
