import { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react";

import { apiClient } from "../api/client";
import type { SessionPayload, SessionUser } from "../types";

type AuthState = "loading" | "authenticated" | "unauthenticated";

type AuthContextValue = {
  state: AuthState;
  user: SessionUser | null;
  refreshSession: () => Promise<void>;
  logout: () => Promise<void>;
};

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

export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
  const [state, setState] = useState<AuthState>("loading");
  const [user, setUser] = useState<SessionUser | null>(null);

  const refreshSession = useCallback(async () => {
    setState("loading");
    try {
      const response = await apiClient.get<SessionPayload>("/auth/me");
      setUser(response.data.user);
      setState("authenticated");
    } catch {
      setUser(null);
      setState("unauthenticated");
    }
  }, []);

  const logout = useCallback(async () => {
    await apiClient.post("/auth/logout");
    setUser(null);
    setState("unauthenticated");
  }, []);

  useEffect(() => {
    void refreshSession();
  }, [refreshSession]);

  const value = useMemo(
    () => ({
      state,
      user,
      refreshSession,
      logout
    }),
    [refreshSession, state, user, logout]
  );

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

export const useAuth = (): AuthContextValue => {
  const context = useContext(AuthContext);
  if (!context) {
    throw new Error("useAuth must be used within AuthProvider");
  }

  return context;
};
