import React from 'react';
import {
  authorizedFetch,
  clearOAuthSession,
  clearTokens,
  completeOAuthCallback,
  loadTokens,
  registerAuthFailureHandler,
  startOAuthFlow,
} from './tokens';
import { ADMIN_LOGIN_PATH } from '../constants';

export type AuthStatus = 'loading' | 'authenticated' | 'unauthenticated';

export interface TenantProfile {
  id: number;
  tenant_id: number;
  name?: string;
  slug?: string;
  email?: string | null;
  event_credits_balance?: number;
  [key: string]: unknown;
}

interface AuthContextValue {
  status: AuthStatus;
  user: TenantProfile | null;
  login: (redirectPath?: string) => void;
  logout: (options?: { redirect?: string }) => void;
  completeLogin: (params: URLSearchParams) => Promise<string | null>;
  refreshProfile: () => Promise<void>;
}

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

export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const [status, setStatus] = React.useState<AuthStatus>('loading');
  const [user, setUser] = React.useState<TenantProfile | null>(null);

  const handleAuthFailure = React.useCallback(() => {
    clearTokens();
    setUser(null);
    setStatus('unauthenticated');
  }, []);

  React.useEffect(() => {
    const unsubscribe = registerAuthFailureHandler(handleAuthFailure);
    return unsubscribe;
  }, [handleAuthFailure]);

  const refreshProfile = React.useCallback(async () => {
    try {
      const response = await authorizedFetch('/api/v1/tenant/me');
      if (!response.ok) {
        throw new Error('Failed to load profile');
      }
      const profile = (await response.json()) as TenantProfile;
      setUser(profile);
      setStatus('authenticated');
    } catch (error) {
      console.error('[Auth] Failed to refresh profile', error);
      handleAuthFailure();
      throw error;
    }
  }, [handleAuthFailure]);

  React.useEffect(() => {
    const searchParams = new URLSearchParams(window.location.search);
    if (searchParams.has('reset-auth') || window.location.pathname === ADMIN_LOGIN_PATH) {
      clearTokens();
      clearOAuthSession();
      setUser(null);
      setStatus('unauthenticated');
    }

    const tokens = loadTokens();
    if (!tokens) {
      setUser(null);
      setStatus('unauthenticated');
      return;
    }

    refreshProfile().catch(() => {
      // refreshProfile already handled failures.
    });
  }, [handleAuthFailure, refreshProfile]);

  const login = React.useCallback((redirectPath?: string) => {
    const target = redirectPath ?? window.location.pathname + window.location.search;
    startOAuthFlow(target);
  }, []);

  const logout = React.useCallback(({ redirect }: { redirect?: string } = {}) => {
    clearTokens();
    clearOAuthSession();
    setUser(null);
    setStatus('unauthenticated');
    if (redirect) {
      window.location.href = redirect;
    }
  }, []);

  const completeLogin = React.useCallback(
    async (params: URLSearchParams) => {
      setStatus('loading');
      try {
        const redirectTarget = await completeOAuthCallback(params);
        await refreshProfile();
        return redirectTarget;
      } catch (error) {
        handleAuthFailure();
        throw error;
      }
    },
    [handleAuthFailure, refreshProfile]
  );

  const value = React.useMemo<AuthContextValue>(
    () => ({ status, user, login, logout, completeLogin, refreshProfile }),
    [status, user, login, logout, completeLogin, refreshProfile]
  );

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

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