import http from "node:http";
import { URL } from "node:url";

import { toNodeHandler } from "better-auth/node";

import { auth, closeAuth, devMailboxEnabled, ensureAuthReady } from "./auth.mjs";
import { listDevMail } from "./dev-mailbox.mjs";

const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
const authPort = Number(process.env.AUTH_PORT || "3001");
const appMode = (process.env.APP_ENV || process.env.NODE_ENV || "development").trim().toLowerCase();
const enforceExplicitCORS = appMode === "staging" || appMode === "production";
const allowedOrigins = parseAllowedOrigins(process.env.CORS_ALLOW_ORIGINS, frontendUrl, enforceExplicitCORS);
const authHandler = toNodeHandler(auth);
let isShuttingDown = false;
let shutdownTimer = null;

function setCorsHeaders(request, response) {
  const requestOrigin = request.headers.origin;
  if (requestOrigin && allowedOrigins.has(requestOrigin)) {
    response.setHeader("Access-Control-Allow-Origin", requestOrigin);
  } else if (!requestOrigin) {
    response.setHeader("Access-Control-Allow-Origin", frontendUrl);
  }
  response.setHeader("Vary", "Origin");
  response.setHeader("Access-Control-Allow-Credentials", "true");
  response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Cookie");
  response.setHeader("Access-Control-Allow-Methods", "GET, POST, PATCH, PUT, DELETE, OPTIONS");
}

const server = http.createServer(async (request, response) => {
  setCorsHeaders(request, response);

  if (request.method === "OPTIONS") {
    response.writeHead(204);
    response.end();
    return;
  }

  const url = new URL(request.url || "/", `http://${request.headers.host || `localhost:${authPort}`}`);

  try {
    if (url.pathname === "/api/dev-mailbox" && request.method === "GET" && devMailboxEnabled) {
      const email = url.searchParams.get("email") || undefined;
      response.writeHead(200, { "Content-Type": "application/json" });
      response.end(JSON.stringify({ data: await listDevMail(email) }));
      return;
    }

    if (url.pathname.startsWith("/api/auth/")) {
      authHandler(request, response);
      return;
    }

    if (url.pathname === "/health" && request.method === "GET") {
      response.writeHead(200, { "Content-Type": "application/json" });
      response.end(JSON.stringify({ ok: true, service: "auth" }));
      return;
    }

    response.writeHead(404, { "Content-Type": "application/json" });
    response.end(JSON.stringify({ error: "Not found" }));
  } catch (error) {
    console.error("[Productier auth] request failed", error);
    response.writeHead(500, { "Content-Type": "application/json" });
    response.end(JSON.stringify({ error: "Internal server error" }));
  }
});

async function bootstrap() {
  try {
    await ensureAuthReady();
  } catch (error) {
    console.error("[Productier auth] startup failed during auth initialization", error);
    process.exit(1);
  }

  server.listen(authPort, () => {
    console.log(`[Productier auth] listening on http://localhost:${authPort}`);
  });
}

async function shutdown(signal) {
  if (isShuttingDown) {
    return;
  }
  isShuttingDown = true;
  console.log(`[Productier auth] received ${signal}, shutting down`);

  shutdownTimer = setTimeout(() => {
    console.error("[Productier auth] forced shutdown after timeout");
    process.exit(1);
  }, 10000);
  shutdownTimer.unref();

  server.close(async closeError => {
    if (closeError) {
      console.error("[Productier auth] server close failed", closeError);
      process.exitCode = 1;
    }
    try {
      await closeAuth();
    } catch (error) {
      console.error("[Productier auth] auth shutdown failed", error);
      process.exitCode = 1;
    } finally {
      if (shutdownTimer) {
        clearTimeout(shutdownTimer);
      }
      process.exit();
    }
  });
}

process.on("SIGINT", () => {
  void shutdown("SIGINT");
});
process.on("SIGTERM", () => {
  void shutdown("SIGTERM");
});

void bootstrap();

function parseAllowedOrigins(raw, fallbackOrigin, strictMode) {
  const origins = new Set();
  if (strictMode && (!raw || raw.trim().length === 0)) {
    throw new Error("CORS_ALLOW_ORIGINS must be set in staging/production");
  }
  const source = raw && raw.trim().length > 0 ? raw : fallbackOrigin;
  source
    .split(",")
    .map(value => value.trim())
    .filter(Boolean)
    .forEach(origin => {
      try {
        origins.add(new URL(origin).origin);
      } catch (error) {
        if (strictMode) {
          throw new Error(`invalid origin in CORS_ALLOW_ORIGINS: ${origin}`);
        }
        console.warn(`[Productier auth] ignoring invalid CORS origin: ${origin}`);
      }
    });

  if (origins.size === 0) {
    if (strictMode) {
      throw new Error("CORS_ALLOW_ORIGINS must include at least one valid origin");
    }
    origins.add(fallbackOrigin);
  }
  return origins;
}
