import { env } from "@code/env/web";
import { redirect } from "react-router";

interface AuthLoaderData {
  readonly token: string | null;
}

const tokenUrl = new URL("/api/auth/convex/token", env.VITE_AUTH_URL);

export const loadAuthToken = async (
  request: Request
): Promise<AuthLoaderData> => {
  const cookie = request.headers.get("cookie");
  if (!cookie) {
    return { token: null };
  }

  const headers = new Headers({ cookie });
  headers.set("host", tokenUrl.host);
  const response = await fetch(tokenUrl, { headers });
  if (response.status === 401) {
    return { token: null };
  }
  if (!response.ok) {
    throw new Response("Authentication service unavailable", { status: 503 });
  }

  const payload: unknown = await response.json();
  if (
    typeof payload !== "object" ||
    payload === null ||
    !("token" in payload) ||
    typeof payload.token !== "string"
  ) {
    throw new Response("Authentication service returned an invalid response", {
      status: 502,
    });
  }
  return { token: payload.token };
};

export const requireAuthToken = async (
  request: Request
): Promise<AuthLoaderData> => {
  const auth = await loadAuthToken(request);
  if (!auth.token) {
    const requestUrl = new URL(request.url);
    const returnTo = `${requestUrl.pathname}${requestUrl.search}`;
    throw redirect(`/login?returnTo=${encodeURIComponent(returnTo)}`);
  }
  return auth;
};

export const redirectAuthenticated = async (
  request: Request
): Promise<AuthLoaderData> => {
  const auth = await loadAuthToken(request);
  if (auth.token) {
    const requestUrl = new URL(request.url);
    const returnTo = requestUrl.searchParams.get("returnTo");
    throw redirect(returnTo?.startsWith("/") ? returnTo : "/");
  }
  return auth;
};
