import { useCallback, useContext, useEffect, useMemo, useState, type ReactNode, createContext } from 'react';
import {
  getAuthMe,
  loginCurator,
  logoutCurator,
  type AuthRole,
  type StaffPermission,
} from '../api/client';

interface AuthContextValue {
  role: AuthRole;
  username?: string;
  permissions: StaffPermission[];
  isCurator: boolean;
  isAdmin: boolean;
  loading: boolean;
  can: (permission: StaffPermission) => boolean;
  login: (username: string, password: string) => Promise<void>;
  logout: () => Promise<void>;
  refresh: () => Promise<void>;
}

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

function applyAuthState(
  me: { role: AuthRole; username?: string; permissions?: StaffPermission[] },
  setRole: (r: AuthRole) => void,
  setUsername: (u: string | undefined) => void,
  setPermissions: (p: StaffPermission[]) => void
) {
  setRole(me.role);
  setUsername(me.username);
  setPermissions(me.role === 'user' ? [] : me.permissions ?? []);
}

export function AuthProvider({ children }: { children: ReactNode }) {
  const [role, setRole] = useState<AuthRole>('user');
  const [username, setUsername] = useState<string | undefined>();
  const [permissions, setPermissions] = useState<StaffPermission[]>([]);
  const [loading, setLoading] = useState(true);

  const refresh = useCallback(async () => {
    const me = await getAuthMe();
    applyAuthState(me, setRole, setUsername, setPermissions);
  }, []);

  useEffect(() => {
    refresh().finally(() => setLoading(false));
  }, [refresh]);

  const login = useCallback(async (user: string, password: string) => {
    const me = await loginCurator(user, password);
    applyAuthState(me, setRole, setUsername, setPermissions);
  }, []);

  const logout = useCallback(async () => {
    await logoutCurator();
    setRole('user');
    setUsername(undefined);
    setPermissions([]);
  }, []);

  const can = useCallback(
    (permission: StaffPermission) => {
      if (role === 'admin') return true;
      if (role !== 'curator') return false;
      return permissions.includes(permission);
    },
    [role, permissions]
  );

  const value = useMemo(
    () => ({
      role,
      username,
      permissions,
      isCurator: role === 'admin' || role === 'curator',
      isAdmin: role === 'admin',
      loading,
      can,
      login,
      logout,
      refresh,
    }),
    [role, username, permissions, loading, can, login, logout, refresh]
  );

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

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