"use client";

import { useRouter } from "next/navigation";
import { createContext, useContext, useEffect, useMemo, useRef, useState } from "react";
import { User } from "@/lib/api";

type AuthContextValue = {
  token: string | null;
  setToken: (value: string | null) => void;
  setUser: (value: User | null) => void;
  logout: () => void;
  user: User | null;
  refreshUser: () => Promise<User | null>;
};

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

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const router = useRouter();
  const [token, setTokenState] = useState<string | null>(null);
  const [user, setUser] = useState<User | null>(null);
  const tokenRef = useRef<string | null>(null);
  const userRef = useRef<User | null>(null);

  useEffect(() => {
    tokenRef.current = token;
  }, [token]);

  useEffect(() => {
    userRef.current = user;
  }, [user]);

  useEffect(() => {
    void fetch("/api/me", { credentials: "include", cache: "no-store" })
      .then(async (response) => {
        if (!response.ok) {
          throw new Error(`HTTP ${response.status}`);
        }
        return (await response.json()) as User;
      })
      .then((current) => {
        setUser(current);
        setTokenState("authenticated");
      })
      .catch(() => {
        if (!tokenRef.current && !userRef.current) {
          setUser(null);
          setTokenState(null);
        }
      });
  }, []);

  const value = useMemo<AuthContextValue>(() => {
    const setToken = (next: string | null) => {
      setTokenState(next);
    };
    return {
      token,
      setToken,
      setUser,
      logout: () => {
        setToken(null);
        void fetch("/api/logout", { method: "POST", credentials: "include" });
        router.push("/login");
      },
      user,
      refreshUser: async () => {
        try {
          const response = await fetch("/api/me", { credentials: "include", cache: "no-store" });
          if (!response.ok) {
            throw new Error(`HTTP ${response.status}`);
          }
          const current = (await response.json()) as User;
          setUser(current);
          setTokenState("authenticated");
          return current;
        } catch {
          if (!userRef.current) {
            setUser(null);
            setTokenState(null);
          }
          return null;
        }
      }
    };
  }, [router, token, user]);

  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}

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