const http = require('http');
const net = require('net');
const path = require('path');
const fs = require('fs');
const { spawn } = require('child_process');

async function getFreePort(start = 3050, end = 3999) {
  for (let port = start; port <= end; port += 1) {
    const isFree = await new Promise((resolve) => {
      const tester = net.createServer()
        .once('error', () => resolve(false))
        .once('listening', () => tester.close(() => resolve(true)))
        .listen(port, '127.0.0.1');
    });
    if (isFree) return port;
  }
  throw new Error('No free local port available for Org Board AI desktop server');
}

async function waitForServer(url, timeoutMs = 30000) {
  const start = Date.now();
  while (Date.now() - start < timeoutMs) {
    const ok = await new Promise((resolve) => {
      const req = http.get(url, (res) => {
        res.resume();
        resolve(res.statusCode >= 200 && res.statusCode < 500);
      });
      req.on('error', () => resolve(false));
      req.setTimeout(2500, () => {
        req.destroy();
        resolve(false);
      });
    });
    if (ok) return true;
    await new Promise((resolve) => setTimeout(resolve, 500));
  }
  throw new Error(`Timed out waiting for local Org Board AI server at ${url}`);
}

async function startLocalServer({ appRoot, dataDir }) {
  fs.mkdirSync(dataDir, { recursive: true });
  const port = await getFreePort();
  const dbPath = path.join(dataDir, 'org-board.db');
  const childEnv = {
    ...process.env,
    PORT: String(port),
    ORG_BOARD_DATA_DIR: dataDir,
    ORG_BOARD_DB_PATH: dbPath,
    ELECTRON_RUN_AS_NODE: '1'
  };
  const child = spawn(process.execPath, [path.join(appRoot, 'server.js')], {
    cwd: appRoot,
    env: childEnv,
    stdio: process.env.ORG_BOARD_DESKTOP_VERBOSE === '1' ? 'pipe' : 'ignore'
  });

  if (child.stdout) {
    child.stdout.on('data', (chunk) => {
      try {
        process.stdout.write(`[desktop-server] ${chunk}`);
      } catch (_) {}
    });
  }
  if (child.stderr) {
    child.stderr.on('data', (chunk) => {
      try {
        process.stderr.write(`[desktop-server] ${chunk}`);
      } catch (_) {}
    });
  }

  const url = `http://127.0.0.1:${port}`;
  await waitForServer(`${url}/api/settings`);

  return {
    child,
    port,
    url,
    dbPath
  };
}

function stopLocalServer(serverHandle) {
  if (!serverHandle?.child || serverHandle.child.killed) return;
  try {
    serverHandle.child.kill('SIGTERM');
  } catch (_) {}
}

module.exports = {
  startLocalServer,
  stopLocalServer
};
