import React, {
  createContext,
  useContext,
  useEffect,
  useMemo,
  useState,
} from 'react';
import { ps } from '@/api/client';
import { authBus } from '@/auth/authBus';
import type { ApplicationValidityResponse } from 'parksmarter-client';

type AuthStatus = 'loading' | 'signedOut' | 'signedIn';

interface AuthState {
  status: AuthStatus;
  validity: ApplicationValidityResponse | null;
  login: (phoneNumber: string, password: string) => Promise<void>;
  logout: () => Promise<void>;
  error: string | null;
}

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

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const [status, setStatus] = useState<AuthStatus>('loading');
  const [validity, setValidity] = useState<ApplicationValidityResponse | null>(null);
  const [error, setError] = useState<string | null>(null);

  // Any 401 from the API (expired/rotated token) bounces us back to sign-in.
  useEffect(() => {
    authBus.onUnauthorized = () => {
      setError('Your session expired — please sign in again.');
      setStatus('signedOut');
    };
    return () => {
      authBus.onUnauthorized = undefined;
    };
  }, []);

  // On launch: bootstrap (seeds SessionId + feature flags) and probe for an
  // existing token by attempting an authenticated read.
  useEffect(() => {
    (async () => {
      try {
        const v = await ps.getApplicationValidity();
        setValidity(v);
        const existing = await ps.tokens.getAuthToken();
        if (existing) {
          await ps.getUserDetail(); // 401 throws -> treated as signed out
          setStatus('signedIn');
        } else {
          setStatus('signedOut');
        }
      } catch {
        setStatus('signedOut');
      }
    })();
  }, []);

  const login = async (phoneNumber: string, password: string) => {
    setError(null);
    try {
      await ps.loginWithPhone({ phoneNumber, password });
      setStatus('signedIn');
    } catch (e: any) {
      // A 201 from /api/Auth means the account needs SMS verification first.
      if (e?.status === 201) setError('Account needs verification. Check your texts.');
      else setError(e?.serverMessage ?? e?.message ?? 'Login failed.');
      throw e;
    }
  };

  const logout = async () => {
    await ps.logoutLocal();
    setStatus('signedOut');
  };

  const value = useMemo<AuthState>(
    () => ({ status, validity, login, logout, error }),
    [status, validity, error],
  );

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

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