import { apiUrl } from "@/lib/apiUrl";
import { applyCsrfHeaders, syncCsrfMetaTag } from "@/lib/csrf";

const AUTH_FLAG_KEY = "spark_auth";

export type SiteUser = {
  username: string;
  roles: string[];
};

export type SiteLoginResult =
  | { ok: true; user: SiteUser }
  | { ok: false; reason: "invalid_credentials" | "csrf" | "network" | "unknown" };

export function isSiteAuthFlagSet(): boolean {
  return typeof sessionStorage !== "undefined" && sessionStorage.getItem(AUTH_FLAG_KEY) === "true";
}

export function setSiteAuthFlag(active: boolean): void {
  if (typeof sessionStorage === "undefined") return;
  if (active) sessionStorage.setItem(AUTH_FLAG_KEY, "true");
  else sessionStorage.removeItem(AUTH_FLAG_KEY);
}

/** Remove all client-side auth markers (sessionStorage). */
export function clearSiteAuthStorage(): void {
  setSiteAuthFlag(false);
}

/** Fetch wrapper for site session cookies + JSON. */
export async function siteFetch(input: string, init: RequestInit = {}): Promise<Response> {
  const headers = new Headers(init.headers);
  if (!headers.has("Accept")) headers.set("Accept", "application/json");
  if (init.body && !headers.has("Content-Type")) headers.set("Content-Type", "application/json");

  const method = init.method?.toUpperCase() ?? "GET";
  if (method !== "GET" && method !== "HEAD" && !headers.has("X-CSRF-TOKEN") && !headers.has("X-XSRF-TOKEN")) {
    applyCsrfHeaders(headers);
  }

  const response = await fetch(apiUrl(input), {
    ...init,
    headers,
    credentials: "include",
    cache: "no-store",
  });

  syncCsrfMetaTag();

  return response;
}

export async function fetchSiteUser(): Promise<SiteUser | null> {
  const res = await siteFetch("/api/site/user");
  if (!res.ok) return null;
  const data = (await res.json()) as { user?: SiteUser };
  return data.user ?? null;
}

export async function siteLogin(username: string, password: string): Promise<SiteLoginResult> {
  const attempt = async (): Promise<Response> =>
    siteFetch("/api/site/login", {
      method: "POST",
      body: JSON.stringify({ username, password }),
    });

  try {
    let res = await attempt();

    if (res.status === 419) {
      syncCsrfMetaTag();
      res = await attempt();
    }

    if (res.status === 419) {
      return { ok: false, reason: "csrf" };
    }

    if (res.status === 422) {
      return { ok: false, reason: "invalid_credentials" };
    }

    if (!res.ok) {
      return { ok: false, reason: "unknown" };
    }

    const data = (await res.json()) as { user?: SiteUser; csrf_token?: string };
    if (data.csrf_token) {
      syncCsrfMetaTag(data.csrf_token);
    } else {
      syncCsrfMetaTag();
    }

    if (!data.user) {
      return { ok: false, reason: "unknown" };
    }

    return { ok: true, user: data.user };
  } catch {
    return { ok: false, reason: "network" };
  }
}

/** Invalidate the server session. Retries once if CSRF was stale. Returns true when session was destroyed. */
export async function siteLogout(): Promise<boolean> {
  const attempt = async (): Promise<Response> =>
    siteFetch("/api/site/logout", { method: "POST" });

  let res = await attempt();

  if (res.status === 419) {
    syncCsrfMetaTag();
    res = await attempt();
  }

  if (!res.ok) {
    return false;
  }

  const data = (await res.json().catch(() => ({}))) as { csrf_token?: string };
  if (data.csrf_token) {
    syncCsrfMetaTag(data.csrf_token);
  } else {
    syncCsrfMetaTag();
  }

  clearSiteAuthStorage();
  return true;
}

/** Authenticated fetch for CMS page endpoints. */
export function cmsPageFetch(apiPath: string): Promise<Response> {
  return siteFetch(apiPath);
}
