import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
  type ReactNode,
} from 'react';
import {
  clearTokens,
  getAccessToken,
  getRefreshToken,
  loadStoredTokens,
  saveTokens,
} from '@/src/api/client';
import * as authApi from '@/src/api/auth.api';
import type { LoginRequest, RegisterRequest, UserInfo } from '@/src/types/auth';

interface AuthContextValue {
  user: UserInfo | null;
  isLoading: boolean;
  isAuthenticated: boolean;
  login: (payload: LoginRequest) => Promise<void>;
  register: (payload: RegisterRequest) => Promise<void>;
  logout: () => Promise<void>;
  refreshSession: () => Promise<void>;
}

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

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

  const refreshSession = useCallback(async () => {
    await loadStoredTokens();
    if (!getAccessToken()) {
      setUser(null);
      return;
    }
    const me = await authApi.fetchCurrentUser();
    setUser(me);
  }, []);

  useEffect(() => {
    (async () => {
      try {
        await refreshSession();
      } catch {
        await clearTokens();
        setUser(null);
      } finally {
        setIsLoading(false);
      }
    })();
  }, [refreshSession]);

  const login = useCallback(async (payload: LoginRequest) => {
    await authApi.login(payload);
    const me = await authApi.fetchCurrentUser();
    setUser(me);
  }, []);

  const register = useCallback(async (payload: RegisterRequest) => {
    await authApi.register(payload);
    const me = await authApi.fetchCurrentUser();
    setUser(me);
  }, []);

  const logout = useCallback(async () => {
    const refresh = await getRefreshToken();
    await authApi.logout(refresh);
    await clearTokens();
    setUser(null);
  }, []);

  const value = useMemo(
    () => ({
      user,
      isLoading,
      isAuthenticated: Boolean(user && getAccessToken()),
      login,
      register,
      logout,
      refreshSession,
    }),
    [user, isLoading, login, register, logout, refreshSession],
  );

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

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

// Re-export for token refresh after external login
export { saveTokens };
