import { createServer, type Server } from "node:http";

export interface DiscordStatus {
  ready: boolean;
  botTag?: string;
}

type StatusProvider = () => DiscordStatus;

export function createStatusServer(getDiscordStatus: StatusProvider): Server {
  const startedAt = new Date();

  return createServer((request, response) => {
    const method = request.method ?? "GET";
    const path = new URL(request.url ?? "/", "http://localhost").pathname;

    response.setHeader("Cache-Control", "no-store");
    response.setHeader("Content-Type", "application/json; charset=utf-8");

    if (method !== "GET" && method !== "HEAD") {
      response.writeHead(405, { Allow: "GET, HEAD" });
      response.end(method === "HEAD" ? undefined : JSON.stringify({ error: "method_not_allowed" }));
      return;
    }

    if (path !== "/" && path !== "/health") {
      response.writeHead(404);
      response.end(method === "HEAD" ? undefined : JSON.stringify({ error: "not_found" }));
      return;
    }

    const discord = getDiscordStatus();
    const healthy = discord.ready;
    const body = JSON.stringify({
      service: "xenosign-discord",
      status: healthy ? "ok" : "starting",
      discord: {
        connected: healthy,
        ...(discord.botTag ? { botTag: discord.botTag } : {}),
      },
      startedAt: startedAt.toISOString(),
      uptimeSeconds: Math.floor(process.uptime()),
    });

    response.writeHead(path === "/health" && !healthy ? 503 : 200);
    response.end(method === "HEAD" ? undefined : body);
  });
}

export function listenStatusServer(server: Server, host: string, port: number): Promise<void> {
  return new Promise((resolve, reject) => {
    const onError = (error: Error): void => reject(error);
    server.once("error", onError);
    server.listen(port, host, () => {
      server.off("error", onError);
      resolve();
    });
  });
}

export function closeStatusServer(server: Server): Promise<void> {
  return new Promise((resolve, reject) => {
    server.close((error) => (error ? reject(error) : resolve()));
  });
}
