import { createContext, useContext, useEffect, useState, type ReactNode } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import { login as apiLogin, logout as apiLogout, me } from '../lib/api/auth.js';
import type { AuthUser } from '../lib/api/auth.js';
import { ApiRequestError } from '../lib/api/client.js';

interface AuthContextValue {
  user: AuthUser | null;
  status: 'loading' | 'authenticated' | 'anonymous';
  login: (username: string, password: string) => Promise<AuthUser>;
  logout: () => Promise<void>;
}

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

export function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<AuthUser | null>(null);
  const [status, setStatus] = useState<AuthContextValue['status']>('loading');
  const qc = useQueryClient();

  // Bootstrap: try /me once. If the refresh interceptor revives a dead access token, this
  // round-trips once; on a hard 401 the server returns anonymous and we show the Login page.
  useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        const u = await me();
        if (!cancelled) {
          setUser(u);
          setStatus('authenticated');
        }
      } catch (err) {
        if (cancelled) return;
        if (err instanceof ApiRequestError && err.status === 401) {
          setStatus('anonymous');
        } else {
          setStatus('anonymous');
        }
      }
    })();
    return () => {
      cancelled = true;
    };
  }, []);

  const login: AuthContextValue['login'] = async (username, password) => {
    const u = await apiLogin(username, password);
    setUser(u);
    setStatus('authenticated');
    return u;
  };

  const logout: AuthContextValue['logout'] = async () => {
    try {
      await apiLogout();
    } catch {
      // Ignore — tokens are best-effort-revoked server side.
    }
    setUser(null);
    setStatus('anonymous');
    qc.clear();
  };

  return (
    <AuthContext.Provider value={{ user, status, login, logout }}>{children}</AuthContext.Provider>
  );
}

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