// Authentication Context - handles user auth state and OIDC flow

import { createContext, useContext, useState, useEffect, useCallback, useMemo } from 'react';

const AuthContext = createContext(null);

export function AuthProvider({ children }) {
  const [user, setUser] = useState(null);
  const [authEnabled, setAuthEnabled] = useState(true);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [expiresAt, setExpiresAt] = useState(null);

  // Check auth status on mount
  useEffect(() => {
    checkAuthStatus();
  }, []);

  // Set up token refresh interval
  useEffect(() => {
    console.log('[AuthContext] Token refresh effect - authEnabled:', authEnabled, 'user:', user?.email, 'expiresAt:', expiresAt);
    if (!authEnabled || !user || !expiresAt) {
      console.log('[AuthContext] Token refresh effect - skipping (missing data)');
      return;
    }

    // Refresh 5 minutes before expiry
    const refreshTime = expiresAt - Date.now() - 5 * 60 * 1000;
    console.log('[AuthContext] Token refresh calculation:', {
      expiresAt,
      now: Date.now(),
      refreshTime,
      willRefreshIn: refreshTime > 0 ? `${Math.round(refreshTime / 1000)}s` : 'NOW'
    });

    if (refreshTime <= 0) {
      // Token already expired or about to, refresh now
      console.log('[AuthContext] Token expired or about to, refreshing NOW');
      refreshToken();
      return;
    }

    console.log(`[AuthContext] Setting refresh timer for ${Math.round(refreshTime / 1000)}s`);
    const timer = setTimeout(refreshToken, refreshTime);
    return () => clearTimeout(timer);
  }, [authEnabled, user, expiresAt]);

  // Check current auth status
  const checkAuthStatus = useCallback(async () => {
    console.log('[AuthContext] checkAuthStatus called');
    try {
      setLoading(true);
      const res = await fetch('/auth/user', {
        credentials: 'include', // Send cookies
      });

      console.log('[AuthContext] /auth/user response status:', res.status);

      if (res.ok) {
        const data = await res.json();
        console.log('[AuthContext] /auth/user data:', JSON.stringify(data));
        console.log('[AuthContext] Setting user:', data.user?.email);
        console.log('[AuthContext] expiresAt from server:', data.expiresAt, 'Date.now():', Date.now());
        setUser(data.user);
        setAuthEnabled(data.authEnabled);
        setExpiresAt(data.expiresAt || null);
        setError(null);
      } else if (res.status === 401) {
        // Not authenticated
        console.log('[AuthContext] Not authenticated (401)');
        setUser(null);
        // Still need to know if auth is enabled
        const statusRes = await fetch('/auth/status', {
          credentials: 'include',
        });
        if (statusRes.ok) {
          const statusData = await statusRes.json();
          setAuthEnabled(statusData.authEnabled);
        }
      } else {
        throw new Error('Failed to check auth status');
      }
    } catch (err) {
      console.error('[Auth] Status check failed:', err);
      setError(err.message);
    } finally {
      setLoading(false);
    }
  }, []);

  // Initiate login - redirect to backend login route
  const login = useCallback((returnTo = '/') => {
    window.location.href = `/auth/login?returnTo=${encodeURIComponent(returnTo)}`;
  }, []);

  // Logout
  const logout = useCallback(async () => {
    try {
      const res = await fetch('/auth/logout', {
        method: 'POST',
        credentials: 'include',
      });

      if (res.ok) {
        const data = await res.json();
        setUser(null);
        setExpiresAt(null);

        // If there's an OIDC logout URL, redirect to it
        if (data.logoutUrl) {
          window.location.href = data.logoutUrl;
        }
      }
    } catch (err) {
      console.error('[Auth] Logout failed:', err);
      // Even if logout fails, clear local state
      setUser(null);
      setExpiresAt(null);
    }
  }, []);

  // Refresh token
  const refreshToken = useCallback(async () => {
    console.log('[AuthContext] refreshToken called');
    try {
      const res = await fetch('/auth/refresh', {
        method: 'POST',
        credentials: 'include',
      });

      console.log('[AuthContext] /auth/refresh response status:', res.status);

      if (res.ok) {
        const data = await res.json();
        console.log('[AuthContext] Token refreshed, new expiresAt:', data.expiresAt);
        setExpiresAt(data.expiresAt);
      } else if (res.status === 401) {
        // Refresh token missing or invalid - but don't log out the user
        // The session cookie is still valid, just the OIDC token refresh failed
        // User will be properly logged out when session expires and /auth/user returns 401
        console.log('[AuthContext] Refresh returned 401 - token refresh unavailable (this is OK, session may still be valid)');
        // Clear expiresAt to prevent repeated refresh attempts
        setExpiresAt(null);
      }
    } catch (err) {
      console.error('[Auth] Token refresh failed:', err);
    }
  }, []);

  // Derived state
  const isAuthenticated = useMemo(() => {
    // If auth is disabled, everyone is "authenticated"
    if (!authEnabled) return true;
    return !!user;
  }, [authEnabled, user]);

  const isAdmin = useMemo(() => {
    return user?.isAdmin || false;
  }, [user]);

  // Context value
  const value = useMemo(() => ({
    // State
    user,
    authEnabled,
    loading,
    error,
    isAuthenticated,
    isAdmin,
    expiresAt,

    // Actions
    login,
    logout,
    refreshToken,
    checkAuthStatus,
  }), [
    user, authEnabled, loading, error, isAuthenticated, isAdmin, expiresAt,
    login, logout, refreshToken, checkAuthStatus,
  ]);

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

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

export default AuthContext;
