import { env } from "@/lib/env";
import { UpdotAuthManager } from "@/lib/updot-auth";
import { Hono } from "hono";

export const UpdotProxyRoutes = new Hono();

UpdotProxyRoutes.all("/admin/*", async (ctx) => {
  const upstream = env.GetString("UPDOT_CORE_BASE_URL");
  if (!upstream) {
    return ctx.json({ error: "Updot Core Base URL not configured" }, 500);
  }
  const path = ctx.req.path;
  const url = `${upstream}${path}`;
  const method = ctx.req.method;

  const incomingUrl = new URL(ctx.req.url);
  const upstreamUrl = new URL(
    incomingUrl.pathname + incomingUrl.search,
    upstream,
  );

  const authManager = UpdotAuthManager.getInstance();

  const doProxyRequest = async (session: {
    admin_session: string;
    admin_session_id: string;
  }) => {
    const headers = new Headers(ctx.req.raw.headers);

    const cookies = [
      `kc_session=${session.admin_session}`,
      `kc_session_id=${session.admin_session_id}`,
      `__sstkn=${session.admin_session}`,
      `__ssid=${session.admin_session_id}`,
      `admin_session=${session.admin_session}`,
      `admin_session_id=${session.admin_session_id}`,
    ].join("; ");

    headers.set("Cookie", cookies);
    headers.delete("host");
    headers.delete("connection");

    const upstreamOrigin = new URL(upstream).origin;
    headers.set("Origin", upstreamOrigin);
    headers.set("Referer", `${upstreamOrigin}/`);

    const body = ["GET", "HEAD"].includes(method)
      ? undefined
      : await ctx.req.text();

    return await fetch(upstreamUrl.toString(), { method, headers, body });
  };

  try {
    let session = await authManager.getOrLogin();
    if (!session) {
      return ctx.json({ error: "Failed to authenticate with Updot Core" }, 401);
    }

    let response = await doProxyRequest(session);

    if ([401, 403].includes(response.status)) {
      console.warn(
        `[UpdotProxy] Got ${response.status}. Invalidating session and retrying...`,
      );
      authManager.invalidate();

      session = await authManager.getOrLogin();
      if (session) {
        response = await doProxyRequest(session);
      }
    }

    const respHeaders = new Headers(response.headers);
    respHeaders.delete("content-encoding");
    respHeaders.delete("content-length");

    if (!response.ok) {
      const errorBody = await response.clone().text();
      console.error(
        `[UpdotProxy] Error (${response.status}) from ${url}:`,
        errorBody,
      );
    }

    return new Response(response.body, {
      status: response.status,
      headers: respHeaders,
    });
  } catch (err) {
    console.error(`[UpdotProxy] Proxy Exception:`, err);
    return ctx.json({ error: "Proxy Failed", details: String(err) }, 502);
  }
});
