// Application-wide authentication state.
//
// The Angular application shared auth state through a root-provided
// AuthenticationService singleton. The idiomatic React equivalent is
// the Context API paired with hooks: AuthProvider owns the token in a
// useState hook and exposes derived values (isLoggedIn, currentUser)
// and actions (login, logout) to any component through useAuth().
//
// A key behavioral improvement over the original: the Angular
// LoginComponent had to poll with a 3-second setTimeout because the
// service saved the token outside Angular's change detection. Here,
// login() is async and resolves after the token is committed to state,
// so the login page can simply await it and navigate — no timers.
import {
  createContext,
  useCallback,
  useContext,
  useMemo,
  useState,
  ReactNode
} from 'react';
import * as authApi from '../api/auth-api';
import { User } from '../models/user';
import {
  getToken,
  saveToken,
  clearToken,
  decodeTokenPayload,
  isTokenValid
} from './token-storage';

interface AuthContextValue {
  isLoggedIn: boolean;
  currentUser: User | null;
  login: (user: User, password: string) => Promise<void>;
  register: (user: User, password: string) => Promise<void>;
  logout: () => void;
}

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

export function AuthProvider({ children }: { children: ReactNode }) {
  // Initialize from localStorage so a valid token survives page reloads.
  const [token, setToken] = useState<string>(() => {
    const stored = getToken();
    return isTokenValid(stored) ? stored : '';
  });

  const handleLogin = useCallback(async (user: User, password: string) => {
    const response = await authApi.login(user, password);
    saveToken(response.token);
    setToken(response.token);
  }, []);

  const handleRegister = useCallback(async (user: User, password: string) => {
    const response = await authApi.register(user, password);
    saveToken(response.token);
    setToken(response.token);
  }, []);

  const handleLogout = useCallback(() => {
    clearToken();
    setToken('');
  }, []);

  const value = useMemo<AuthContextValue>(() => {
    const loggedIn = isTokenValid(token);
    const payload = loggedIn ? decodeTokenPayload(token) : null;
    return {
      isLoggedIn: loggedIn,
      currentUser:
        payload && payload.email && payload.name
          ? { email: payload.email, name: payload.name }
          : null,
      login: handleLogin,
      register: handleRegister,
      logout: handleLogout
    };
  }, [token, handleLogin, handleRegister, handleLogout]);

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

// Custom hook so components never touch the raw context object.
export function useAuth(): AuthContextValue {
  const context = useContext(AuthContext);
  if (!context) {
    throw new Error('useAuth must be used inside an AuthProvider');
  }
  return context;
}
