/**
 * Port Allocator
 *
 * Finds the next available port for the gateway.
 * Only called once when the gateway first starts — subsequent previews
 * reuse the same gateway port.
 */

import { createServer } from 'node:net';
import { createModuleLogger } from '../logger/index.js';

const log = createModuleLogger('preview:port');

/** Starting port for preview deployments */
const BASE_PORT = 9100;

/** Maximum port to try before giving up */
const MAX_PORT = 9200;

/**
 * Allocate the next available port by performing a bind test.
 *
 * @returns An available port number
 * @throws If no port is available in the range
 */
export async function allocatePort(): Promise<number> {
  for (let port = BASE_PORT; port < MAX_PORT; port++) {
    if (await isPortAvailable(port)) {
      log.info({ port }, 'allocated port');
      return port;
    }
  }

  throw new Error(`No available ports in range ${BASE_PORT}-${MAX_PORT}`);
}

/**
 * Test if a port is available by attempting to bind to it.
 */
async function isPortAvailable(port: number): Promise<boolean> {
  return new Promise((resolve) => {
    const server = createServer();

    server.once('error', () => {
      resolve(false);
    });

    server.listen(port, '127.0.0.1', () => {
      server.close(() => {
        resolve(true);
      });
    });
  });
}
