"use client";

import {
  createContext,
  useContext,
  useState,
  useEffect,
  useCallback,
  ReactNode,
} from "react";
import { api, setToken, clearToken, getToken } from "@/lib/apiClient";
import type { UserPublic } from "@/types";

// ─── sessionStorage helpers ───────────────────────────────────────────────────

const USER_KEY = "__ab_user__";

function persistUser(u: UserPublic) {
  if (typeof window !== "undefined")
    sessionStorage.setItem(USER_KEY, JSON.stringify(u));
}

function readUser(): UserPublic | null {
  if (typeof window === "undefined") return null;
  try {
    return JSON.parse(sessionStorage.getItem(USER_KEY) ?? "null");
  } catch {
    return null;
  }
}

function dropUser() {
  if (typeof window !== "undefined") sessionStorage.removeItem(USER_KEY);
}

// ─── Context shape ────────────────────────────────────────────────────────────

interface AuthState {
  user: UserPublic | null;
  isLoading: boolean;
  isAuthenticated: boolean;
}

interface AuthContextValue extends AuthState {
  login: (token: string, user: UserPublic) => void;
  logout: () => Promise<void>;
  refreshUser: () => Promise<void>;
}

const Ctx = createContext<AuthContextValue | null>(null);

// ─── Provider ─────────────────────────────────────────────────────────────────

export function AuthProvider({ children }: { children: ReactNode }) {
  const [state, setState] = useState<AuthState>({
    user: null,
    isLoading: true,
    isAuthenticated: false,
  });

  useEffect(() => {
    // 1️⃣  Fast path — token & user survived a same-tab page reload
    const token = getToken();
    const user = readUser();

    if (token && user) {
      setState({ user, isLoading: false, isAuthenticated: true });
      // Silently refresh token in background (fire-and-forget)
      api<{ accessToken: string }>("/auth/refresh", { method: "POST", auth: false })
        .then((d) => setToken(d.accessToken))
        .catch(() => {});
      return;
    }

    // 2️⃣  Slow path — new tab or first visit; try the httpOnly refresh cookie
    api<{ accessToken: string }>("/auth/refresh", { method: "POST", auth: false })
      .then(async (d) => {
        setToken(d.accessToken);
        const me = await api<UserPublic>("/users/me");
        persistUser(me);
        setState({ user: me, isLoading: false, isAuthenticated: true });
      })
      .catch(() => {
        setState({ user: null, isLoading: false, isAuthenticated: false });
      });
  }, []);

  const login = useCallback((token: string, user: UserPublic) => {
    setToken(token);
    persistUser(user);
    setState({ user, isLoading: false, isAuthenticated: true });
  }, []);

  const logout = useCallback(async () => {
    try { await api("/auth/logout", { method: "POST" }); } catch {}
    clearToken();
    dropUser();
    setState({ user: null, isLoading: false, isAuthenticated: false });
  }, []);

  const refreshUser = useCallback(async () => {
    try {
      const me = await api<UserPublic>("/users/me");
      persistUser(me);
      setState((s) => ({ ...s, user: me }));
    } catch {}
  }, []);

  return (
    <Ctx.Provider value={{ ...state, login, logout, refreshUser }}>
      {children}
    </Ctx.Provider>
  );
}

// ─── Hook ─────────────────────────────────────────────────────────────────────

export function useAuth() {
  const ctx = useContext(Ctx);
  if (!ctx) throw new Error("useAuth must be inside AuthProvider");
  return ctx;
}
