/**
 * Authentication Context
 * Provides unified authentication interface that works with both:
 * - Backend token exchange (localhost/development)
 * - Auth0 Provider (production)
 */

import { createContext, useContext, useEffect, useState, ReactNode, useRef } from 'react';
import { Auth0Provider, useAuth0 as useAuth0Hook } from '@auth0/auth0-react';
import { TokenManager, isTokenExpired } from '../utils/tokenManager';
import { exchangeCodeForTokens, refreshAccessToken, getCurrentUser, logout as logoutApi } from '../services/authApi';

interface User {
  userId?: string;
  employeeId?: string;
  email?: string;
  firstName?: string;
  lastName?: string;
  displayName?: string;
  department?: string;
  designation?: string;
  isAdmin?: boolean;
  sub?: string;
  name?: string;
  picture?: string;
  nickname?: string;
}

interface AuthContextType {
  isAuthenticated: boolean;
  isLoading: boolean;
  user: User | null;
  error: Error | null;
  login: () => Promise<void>;
  logout: () => Promise<void>;
  getAccessTokenSilently: () => Promise<string | null>;
  refreshTokenSilently: () => Promise<void>;
}

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

interface AuthProviderProps {
  children: ReactNode;
}

/**
 * Check if running on localhost
 */
const isLocalhost = (): boolean => {
  return (
    window.location.hostname === 'localhost' ||
    window.location.hostname === '127.0.0.1' ||
    window.location.hostname === ''
  );
};

/**
 * Backend-based Auth Provider (for localhost)
 */
function BackendAuthProvider({ children }: { children: ReactNode }) {
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const [isLoading, setIsLoading] = useState(true);
  const [user, setUser] = useState<User | null>(null);
  const [error, setError] = useState<Error | null>(null);
  const [isLoggingOut, setIsLoggingOut] = useState(false);

  // Check authentication status on mount
  // Only check if we're not in the middle of a logout process
  useEffect(() => {
    // PRIORITY 1: Check for logout flags in sessionStorage (survives page reload during logout)
    const logoutFlag = sessionStorage.getItem('__logout_in_progress__');
    const forceLogout = sessionStorage.getItem('__force_logout__');
    
    if (logoutFlag === 'true' || forceLogout === 'true') {
      console.log('🔴 Logout flag detected - PREVENTING auto-authentication');
      console.log('🔴 Clearing ALL authentication data and showing login screen');
      
      // Remove flags
      sessionStorage.removeItem('__logout_in_progress__');
      sessionStorage.removeItem('__force_logout__');
      
      // Clear all tokens one more time (aggressive)
      TokenManager.clearAll();
      
      // Also manually clear everything
      try {
        localStorage.clear();
        sessionStorage.clear();
      } catch (e) {
        console.error('Error clearing storage:', e);
      }
      
      // Set unauthenticated state
      setIsAuthenticated(false);
      setUser(null);
      setIsLoading(false);
      setError(null);
      
      console.log('🔴 Logout complete - user should see login screen');
      return;
    }
    
    // PRIORITY 2: Check if URL has logout parameter (from redirect)
    const urlParams = new URLSearchParams(window.location.search);
    if (urlParams.has('logout')) {
      console.log('🔴 Logout parameter in URL - clearing everything');
      TokenManager.clearAll();
      localStorage.clear();
      sessionStorage.clear();
      setIsAuthenticated(false);
      setUser(null);
      setIsLoading(false);
      // Clean URL
      window.history.replaceState({}, document.title, '/');
      return;
    }
    
    // PRIORITY 3: Check if this is a logout redirect by checking if all tokens are cleared
    const token = TokenManager.getAccessToken();
    const refreshToken = TokenManager.getRefreshToken();
    const userData = TokenManager.getUserData();
    const hasAuthData = token || refreshToken || userData;
    
    // If no auth data exists, we're likely after a logout - set unauthenticated state immediately
    if (!hasAuthData) {
      console.log('🔴 No auth data found - setting unauthenticated state');
      setIsAuthenticated(false);
      setUser(null);
      setIsLoading(false);
      return;
    }
    
    // PRIORITY 4: Only check auth status if we have some auth data AND we're not logging out
    if (!isLoggingOut) {
      checkAuthStatus();
    } else {
      console.log('🔴 Skipping checkAuthStatus - logout in progress');
      setIsLoading(false);
    }
  }, [isLoggingOut]);

  // Silent refresh interval
  useEffect(() => {
    if (!isAuthenticated) return;

    const checkAndRefresh = async () => {
      const token = TokenManager.getAccessToken();
      if (token && isTokenExpired(token, 5)) {
        // Token expires in less than 5 minutes, refresh it
        try {
          await refreshTokenSilently();
        } catch (error) {
          console.error('Silent refresh failed:', error);
        }
      }
    };

    // Check every 5 minutes
    const interval = setInterval(checkAndRefresh, 5 * 60 * 1000);
    return () => clearInterval(interval);
  }, [isAuthenticated]);

  // Handle callback from OAuth redirect
  // Use ref to prevent duplicate calls (React StrictMode runs effects twice in dev)
  const callbackProcessedRef = useRef(false);
  
  useEffect(() => {
    // Skip if already processed or not on callback page
    if (callbackProcessedRef.current || window.location.pathname !== '/login/callback') {
      return;
    }

    const handleCallback = async () => {
      // Mark as processed immediately to prevent duplicate calls
      callbackProcessedRef.current = true;
      
      const urlParams = new URLSearchParams(window.location.search);
      const code = urlParams.get('code');
      const errorParam = urlParams.get('error');

      // Clean URL immediately to prevent re-running on re-renders
      window.history.replaceState({}, document.title, '/login/callback');

      if (errorParam) {
        setError(new Error(`Authentication error: ${errorParam}`));
        setIsLoading(false);
        return;
      }

      if (!code) {
        setIsLoading(false);
        return;
      }

      try {
        setIsLoading(true);
        setIsAuthenticated(false);
        setError(null);
        
        // IMPORTANT: redirectUri must match the one used in initial Okta authorization request
        // This is the frontend callback URL, NOT the backend URL
        // Backend will use this same URI when exchanging code with Okta
        const redirectUri = `${window.location.origin}/login/callback`;
        console.log('📥 Authorization Code Received:', {
          code: code.substring(0, 10) + '...',
          redirectUri,
          fullUrl: window.location.href,
          note: 'redirectUri is frontend URL (not backend) - must match Okta registration',
        });
        
        const result = await exchangeCodeForTokens(code, redirectUri);
        
        setUser(result.user);
        setIsAuthenticated(true);
        setError(null);
        
        // Clean URL after success
        window.history.replaceState({}, document.title, '/');
      } catch (err: any) {
        console.error('❌ Token exchange error in AuthContext:', err);
        setError(err);
        setIsAuthenticated(false);
        setUser(null);
        // Reset ref on error so user can retry if needed
        callbackProcessedRef.current = false;
      } finally {
        setIsLoading(false);
      }
    };

    handleCallback();
  }, []); // Empty deps - only run once on mount

  const checkAuthStatus = async () => {
    // Don't check auth status if we're in the middle of logging out
    if (isLoggingOut) {
      console.log('🔴 Skipping checkAuthStatus - logout in progress');
      setIsLoading(false);
      return;
    }
    
    try {
      setIsLoading(true);
      
      const token = TokenManager.getAccessToken();
      const storedUser = TokenManager.getUserData();
      
      console.log('🔍 Checking auth status:', { hasToken: !!token, hasUser: !!storedUser, isLoggingOut });

      // If no token at all, user is not authenticated
      if (!token) {
        console.log('🔍 No token found - setting unauthenticated');
        setIsAuthenticated(false);
        setUser(null);
        setIsLoading(false);
        return;
      }

      // Check if token is expired
      if (isTokenExpired(token)) {
        // Token expired, try to refresh
        try {
          await refreshTokenSilently();
          // Refresh succeeded, check again
          const newToken = TokenManager.getAccessToken();
          if (newToken && !isTokenExpired(newToken)) {
            const refreshedUser = TokenManager.getUserData();
            if (refreshedUser) {
              setUser(refreshedUser);
              setIsAuthenticated(true);
            } else {
              // Fetch user data
              try {
                const userData = await getCurrentUser();
                setUser(userData);
                TokenManager.setUserData(userData);
                setIsAuthenticated(true);
              } catch {
                // Token might be invalid, clear everything
                TokenManager.clearAll();
                setIsAuthenticated(false);
                setUser(null);
              }
            }
          } else {
            // Refresh failed, user is logged out
            TokenManager.clearAll();
            setIsAuthenticated(false);
            setUser(null);
          }
        } catch {
          // Refresh failed, clear everything
          TokenManager.clearAll();
          setIsAuthenticated(false);
          setUser(null);
        }
      } else {
        // Token is valid
        if (storedUser) {
          setUser(storedUser);
          setIsAuthenticated(true);
        } else {
          // Fetch user data to ensure token is still valid
          try {
            const userData = await getCurrentUser();
            setUser(userData);
            TokenManager.setUserData(userData);
            setIsAuthenticated(true);
          } catch {
            // Token might be invalid, clear everything
            TokenManager.clearAll();
            setIsAuthenticated(false);
            setUser(null);
          }
        }
      }
    } catch (err: any) {
      console.error('Error checking auth status:', err);
      setError(err);
      TokenManager.clearAll();
      setIsAuthenticated(false);
      setUser(null);
    } finally {
      setIsLoading(false);
    }
  };

  const login = async () => {
    try {
      setError(null);
      // Redirect to Okta login
      const oktaDomain = 'https://dev-830839.oktapreview.com';
      const clientId = '0oa2j8slwj5S4bG5k0h8';
      const redirectUri = `${window.location.origin}/login/callback`;
      const responseType = 'code';
      const scope = 'openid profile email';
      const state = Math.random().toString(36).substring(7);

      const authUrl = `${oktaDomain}/oauth2/default/v1/authorize?` +
        `client_id=${clientId}&` +
        `redirect_uri=${encodeURIComponent(redirectUri)}&` +
        `response_type=${responseType}&` +
        `scope=${encodeURIComponent(scope)}&` +
        `state=${state}`;

      window.location.href = authUrl;
    } catch (err: any) {
      setError(err);
      throw err;
    }
  };

  const logout = async () => {
    console.log('🚪 LOGOUT FUNCTION CALLED - Starting logout process');
    console.log('🚪 Current auth state:', { isAuthenticated, hasUser: !!user, isLoading });
    
    try {
      // Set logout flag to prevent auto-authentication after redirect
      sessionStorage.setItem('__logout_in_progress__', 'true');
      setIsLoggingOut(true);
      
      console.log('🚪 Step 1: Resetting auth state...');
      // Reset auth state FIRST to prevent any re-authentication
      setIsAuthenticated(false);
      setUser(null);
      setError(null);
      setIsLoading(true); // Set loading to prevent checkAuthStatus from running
      console.log('🚪 Step 1: Auth state reset complete');
      
      // Call backend logout API to clear server-side session and httpOnly cookies
      // IMPORTANT: This MUST be called before clearing local storage to clear httpOnly cookies
      try {
        console.log('🚪 Step 2: Calling backend logout API to clear httpOnly cookies...');
        await logoutApi();
        console.log('🚪 Step 2: Backend logout API completed - httpOnly cookies should be cleared');
      } catch (err) {
        console.error('🚪 Logout API error:', err);
        console.warn('🚪 Backend logout failed - httpOnly cookies may not be cleared');
        // Continue with logout even if API call fails
      }
      
      // Clear all authentication data
      console.log('========================================');
      console.log('LOGOUT - Clearing all authentication data');
      console.log('========================================');
      
      // Use TokenManager.clearAll() which does comprehensive cleanup
      TokenManager.clearAll();
      console.log('tryng to clrear all(localStorage and sessionStorage)')
      // Double-check: Clear everything one more time as backup
      try {
        // Get all localStorage keys and remove them
        const localStorageKeys: string[] = [];
        for (let i = 0; i < localStorage.length; i++) {
          const key = localStorage.key(i);
          if (key) localStorageKeys.push(key);
        }
        localStorageKeys.forEach(key => {
          try {
            localStorage.removeItem(key);
          } catch (e) {
            console.warn(`Failed to remove localStorage key ${key}:`, e);
          }
        });
        localStorage.clear();
        
        // Get all sessionStorage keys and remove them
        const sessionStorageKeys: string[] = [];
        for (let i = 0; i < sessionStorage.length; i++) {
          const key = sessionStorage.key(i);
          if (key) sessionStorageKeys.push(key);
        }
        sessionStorageKeys.forEach(key => {
          try {
            sessionStorage.removeItem(key);
          } catch (e) {
            console.warn(`Failed to remove sessionStorage key ${key}:`, e);
          }
        });
        sessionStorage.clear();
        
        console.log('Final verification - Storage cleared:');
        console.log(`localStorage.length: ${localStorage.length}`);
        console.log(`sessionStorage.length: ${sessionStorage.length}`);
        
        if (localStorage.length > 0) {
          console.error('ERROR: localStorage still has items:', Object.keys(localStorage));
        }
        if (sessionStorage.length > 0) {
          console.error('ERROR: sessionStorage still has items:', Object.keys(sessionStorage));
        }
      } catch (e) {
        console.error('Error in final cleanup:', e);
      }
      
      // Final verification BEFORE redirect
      console.log('All authentication data cleared. Final verification:');
      console.log(`localStorage.length: ${localStorage.length}`);
      console.log(`sessionStorage.length: ${sessionStorage.length}`);
      
      if (localStorage.length > 0) {
        console.error('CRITICAL: localStorage still has items before redirect!', Object.keys(localStorage));
        // Force clear one more time
        const remainingKeys = Object.keys(localStorage);
        remainingKeys.forEach(key => localStorage.removeItem(key));
        localStorage.clear();
      }
      if (sessionStorage.length > 0) {
        console.error('CRITICAL: sessionStorage still has items before redirect!', Object.keys(sessionStorage));
        const remainingKeys = Object.keys(sessionStorage);
        remainingKeys.forEach(key => sessionStorage.removeItem(key));
        sessionStorage.clear();
      }
      
      console.log('Redirecting to login...');
      
      // Ensure logout flag is set before redirect
      sessionStorage.setItem('__logout_in_progress__', 'true');
      
      // Small delay to ensure sessionStorage is written before redirect
      await new Promise(resolve => setTimeout(resolve, 50));
      
      // Use replace instead of href to prevent browser history issues
      // DON'T use setTimeout - redirect immediately after clearing
      if (isLocalhost()) {
        // Direct redirect to login page for localhost - force full page reload
        // Add timestamp to force fresh page load
        window.location.replace('/?logout=' + Date.now());
      } else {
        // For production, redirect to Okta logout then to login
        const oktaDomain = 'https://dev-830839.oktapreview.com';
        const loginUrl = `${window.location.origin}/?logout=${Date.now()}`;
        const logoutUrl = `${oktaDomain}/oauth2/default/v1/logout?post_logout_redirect_uri=${encodeURIComponent(loginUrl)}`;
        window.location.replace(logoutUrl);
      }
    } catch (error) {
      console.error('Logout error:', error);
      // Force redirect even on error
      localStorage.clear();
      sessionStorage.clear();
      window.location.replace('/');
    }
  };

  const getAccessTokenSilently = async (): Promise<string | null> => {
    const token = TokenManager.getAccessToken();
    if (token && !isTokenExpired(token)) {
      return token;
    }

    // Try to refresh
    try {
      await refreshTokenSilently();
      return TokenManager.getAccessToken();
    } catch {
      return null;
    }
  };

  const refreshTokenSilently = async (): Promise<void> => {
    try {
      const newToken = await refreshAccessToken();
      if (newToken) {
        // Token refreshed successfully
        return;
      }
      throw new Error('Failed to refresh token');
    } catch (err) {
      TokenManager.clearAll();
      setIsAuthenticated(false);
      setUser(null);
      throw err;
    }
  };

  const value: AuthContextType = {
    isAuthenticated,
    isLoading,
    user,
    error,
    login,
    logout,
    getAccessTokenSilently,
    refreshTokenSilently,
  };

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

/**
 * Auth0-based Auth Provider (for production)
 */
function Auth0AuthProvider({ children }: { children: ReactNode }) {
  return (
    <Auth0Provider
      domain="https://dev-830839.oktapreview.com/oauth2/default/v1"
      clientId="0oa2j8slwj5S4bG5k0h8"
      authorizationParams={{
        redirect_uri: window.location.origin + '/login/callback',
      }}
      onRedirectCallback={(appState) => {
        console.log('Auth0 Redirect Callback:', {
          appState,
          returnTo: appState?.returnTo || window.location.pathname,
        });
      }}
    >
      <Auth0ContextWrapper>{children}</Auth0ContextWrapper>
    </Auth0Provider>
  );
}

/**
 * Wrapper to convert Auth0 hook to our context format
 */
function Auth0ContextWrapper({ children }: { children: ReactNode }) {
  const {
    isAuthenticated: auth0IsAuthenticated,
    isLoading: auth0IsLoading,
    user: auth0User,
    error: auth0Error,
    loginWithRedirect,
    logout: logoutAuth0,
    getAccessTokenSilently: getAuth0Token,
  } = useAuth0Hook();

  const getAccessTokenSilently = async (): Promise<string | null> => {
    try {
      return await getAuth0Token();
    } catch {
      return null;
    }
  };

  const refreshTokenSilently = async (): Promise<void> => {
    // Auth0 handles refresh automatically
    try {
      await getAuth0Token();
    } catch {
      // Silently fail, Auth0 will handle it
    }
  };

  const value: AuthContextType = {
    isAuthenticated: auth0IsAuthenticated,
    isLoading: auth0IsLoading,
    user: auth0User as User | null,
    error: auth0Error as Error | null,
    login: loginWithRedirect,
    logout: logoutAuth0,
    getAccessTokenSilently,
    refreshTokenSilently,
  };

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

/**
 * Main Auth Provider - conditionally uses backend or Auth0
 */
export function AuthProvider({ children }: AuthProviderProps) {
  if (isLocalhost()) {
    return <BackendAuthProvider>{children}</BackendAuthProvider>;
  }
  return <Auth0AuthProvider>{children}</Auth0AuthProvider>;
}

/**
 * Hook to use auth context
 */
export function useAuth(): AuthContextType {
  const context = useContext(AuthContext);
  if (context === undefined) {
    throw new Error('useAuth must be used within an AuthProvider');
  }
  return context;
}

