import {
  createContext,
  useContext,
  useEffect,
  useState,
  useCallback,
  type ReactNode,
} from "react";
import {
  login as apiLogin,
  logout as apiLogout,
  getMe,
  refreshToken as apiRefreshToken,
} from "../api/auth";
import type { User } from "../types/models";
import ChangePasswordModal from "../components/ChangePasswordModal";

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

interface AuthState {
  user: User | null;
  isAuthenticated: boolean;
  isLoading: boolean;
  login: (username: string, password: string) => Promise<void>;
  logout: () => void;
}

const AuthContext = createContext<AuthState | undefined>(undefined);

/* ── Provider ─────────────────────────────────────────────────────── */

export function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<User | null>(null);
  const [isLoading, setIsLoading] = useState(true);

  const refreshUser = useCallback(async () => {
    try {
      const me = await getMe();
      setUser(me);
    } catch {
      setUser(null);
    }
  }, []);

  useEffect(() => {
    refreshUser().finally(() => setIsLoading(false));
  }, [refreshUser]);

  // Proactively renew the session cookie while the app is open, so an
  // actively-used session never actually reaches the hard 8-hour expiry
  // (relying solely on the reactive on-401 refresh risks losing the race
  // against the token's own expiry — see api/client.ts).
  useEffect(() => {
    if (!user) return;
    const PROACTIVE_REFRESH_INTERVAL_MS = 20 * 60 * 1000;
    const id = setInterval(() => {
      apiRefreshToken().catch(() => {
        // Reactive on-401 handling in api/client.ts takes over from here.
      });
    }, PROACTIVE_REFRESH_INTERVAL_MS);
    return () => clearInterval(id);
  }, [user]);

  const login = useCallback(async (username: string, password: string) => {
    await apiLogin(username, password);
    const me = await getMe();
    setUser(me);
  }, []);

  const logout = useCallback(async () => {
    await apiLogout();
    setUser(null);
  }, []);

  const mustChangePassword = user?.must_change_password === true;

  return (
    <AuthContext.Provider
      value={{
        user,
        isAuthenticated: user !== null,
        isLoading,
        login,
        logout,
      }}
    >
      {children}
      {mustChangePassword && (
        <ChangePasswordModal isForced onSuccess={refreshUser} />
      )}
    </AuthContext.Provider>
  );
}

/* ── Hook ─────────────────────────────────────────────────────────── */

export function useAuth(): AuthState {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error("useAuth must be used within <AuthProvider>");
  return ctx;
}
