import { readFileSync } from "node:fs";
import { dirname, resolve } from "node:path";

export interface MockServer {
  url: string;
  port: number;
  stop: () => Promise<void>;
}

/**
 * Start a Mockoon mock server from a mock.json file.
 * Returns a handle with the server URL and a stop function.
 */
export async function createMockServer(mockJsonPath: string, port?: number): Promise<MockServer> {
  const { MockoonServer, createLoggerInstance, listenServerEvents } =
    await import("@mockoon/commons-server");
  type Environment = import("@mockoon/commons").Environment;

  const resolvedPath = resolve(mockJsonPath);
  const environment = JSON.parse(readFileSync(resolvedPath, "utf-8")) as Environment;
  if (port !== undefined) {
    environment.port = port;
  }
  const actualPort = environment.port;

  const logger = createLoggerInstance(null);
  const server = new MockoonServer(environment, {
    environmentDirectory: dirname(resolvedPath),
    enableAdminApi: false,
    disableTls: true,
    enableRandomLatency: false,
    maxTransactionLogs: 100,
    envVarsPrefix: "MOCKOON_",
  });

  listenServerEvents(server, environment, logger, false);

  await new Promise<void>((resolve, reject) => {
    server.on("started", resolve);
    server.on("error", (errorCode, originalError) => {
      reject(originalError ?? new Error(`Mockoon error: ${errorCode}`));
    });
    server.start();
  });

  return {
    url: `http://127.0.0.1:${actualPort}`,
    port: actualPort,
    stop: () =>
      new Promise<void>((resolve) => {
        server.on("stopped", resolve);
        server.stop();
      }),
  };
}
