/**
 * Port finder — detect available ports using the bind approach.
 * This is the canonical Node.js pattern: try to listen → success = free, EADDRINUSE = taken.
 */
import net from 'net';

/** Check if a port is in use on localhost (bind approach — no false positives).
 *  Binds IPv4 loopback only — intentional: all MindOS services pin
 *  HOSTNAME/MCP_HOST to 127.0.0.1, so ::1-only listeners are irrelevant here. */
export function isPortInUse(port: number): Promise<boolean> {
  return new Promise((resolve) => {
    const server = net.createServer();
    server.once('error', (err: NodeJS.ErrnoException) => {
      // EADDRINUSE = port taken; EACCES = no permission (treat as taken)
      resolve(true);
    });
    server.listen(port, '127.0.0.1', () => {
      server.close(() => resolve(false));
    });
  });
}

/**
 * Wait for a specific port to become available (e.g. after killing an orphaned process).
 * Returns true if the port freed up, false if still in use after timeout.
 */
export async function waitForPortRelease(port: number, maxWaitMs = 5000): Promise<boolean> {
  const interval = 300;
  const maxAttempts = Math.ceil(maxWaitMs / interval);
  for (let i = 0; i < maxAttempts; i++) {
    if (!(await isPortInUse(port))) return true;
    await new Promise(r => setTimeout(r, interval));
  }
  return false;
}

/**
 * Find an available port starting from the given port.
 * Tries up to 30 consecutive ports, clamped to valid range (1-65535).
 */
export async function findAvailablePort(start: number, maxAttempts = 30): Promise<number> {
  for (let i = 0; i < maxAttempts; i++) {
    const port = start + i;
    if (port > 65535) break; // Don't try invalid ports
    const inUse = await isPortInUse(port);
    if (!inUse) return port;
  }
  const end = Math.min(start + maxAttempts - 1, 65535);
  const err = new Error(`No available port found in range ${start}-${end}`);
  (err as Error & { code: string }).code = 'ERR_NO_PORT';
  throw err;
}
