import React, { createContext, useContext, useEffect, useState, useRef } from 'react';
import type { User, Session } from '@supabase/supabase-js';
import { supabase } from '@/integrations/supabase/client';
import type { Profile } from '@/types/database';
import { toast } from '@/hooks/use-toast';

interface AuthContextType {
  user: User | null;
  session: Session | null;
  profile: Profile | null;
  loading: boolean;
  pendingEmail: string | null;
  sessionError: string | null;
  signOut: () => Promise<void>;
  refreshProfile: () => Promise<void>;
  verifySession: () => Promise<boolean>;
  clearPendingEmail: () => void;
}

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

function AuthProviderComponent({ children }: { children: React.ReactNode }) {
  const [user, setUser] = useState<User | null>(null);
  const [session, setSession] = useState<Session | null>(null);
  const [profile, setProfile] = useState<Profile | null>(null);
  const [loading, setLoading] = useState(true);
  const [pendingEmail, setPendingEmail] = useState<string | null>(null);
  const [sessionError, setSessionError] = useState<string | null>(null);
  
  // Refs for lifecycle and cleanup management
  const isMountedRef = useRef(true);
  const profileFetchTimeoutRef = useRef<NodeJS.Timeout | null>(null);
  const profileRetryCountRef = useRef(0);
  const sessionVerifiedRef = useRef(false);
  const novuUpdateTimeoutRef = useRef<NodeJS.Timeout | null>(null);
  const previousEmailRef = useRef<string | null>(null);
  const loadingTimeoutRef = useRef<NodeJS.Timeout | null>(null);
  const loadingStateRef = useRef(loading);

  const fetchProfile = async (userId: string, retryCount = 0, onComplete?: () => void) => {
    try {
      const { data, error } = await supabase
        .from('profiles')
        .select(`*, location:locations(*)`)
        .eq('user_id', userId)
        .maybeSingle();

      if (error && error.code !== 'PGRST116') {
        console.error('[Auth] Error fetching profile:', error);
        
        // Retry up to 3 times with exponential backoff
        if (retryCount < 3 && isMountedRef.current) {
          const delay = Math.pow(2, retryCount) * 1000; // 1s, 2s, 4s
          console.log(`[Auth] Retrying profile fetch in ${delay}ms (attempt ${retryCount + 1}/3)`);
          setTimeout(() => {
            if (isMountedRef.current) {
              fetchProfile(userId, retryCount + 1, onComplete);
            }
          }, delay);
          return;
        }
        
        // All retries exhausted - complete anyway
        if (isMountedRef.current) {
          console.warn('[Auth] Profile fetch failed after 3 retries');
          setProfile(null);
          onComplete?.();
        }
        return;
      }

      // Success - update state and complete
      if (isMountedRef.current) {
        setProfile(data as Profile);
        profileRetryCountRef.current = 0;
        onComplete?.();
      }
    } catch (error) {
      console.error('[Auth] Error fetching profile:', error);
      
      // Retry logic for network errors
      if (retryCount < 3 && isMountedRef.current) {
        const delay = Math.pow(2, retryCount) * 1000;
        setTimeout(() => {
          if (isMountedRef.current) {
            fetchProfile(userId, retryCount + 1, onComplete);
          }
        }, delay);
      } else {
        // All retries exhausted
        if (isMountedRef.current) {
          setProfile(null);
          onComplete?.();
        }
      }
    }
  };

  const refreshProfile = async () => {
    if (user) {
      await fetchProfile(user.id);
    }
  };

  // Verify session is still valid
  const verifySession = async (updateLoadingState = false) => {
    if (updateLoadingState && isMountedRef.current) {
      setLoading(true);
    }
    
    try {
      const { data: { session }, error } = await supabase.auth.getSession();
      
      if (error) {
        console.error('[Auth] Session verification failed:', error);
        setSessionError(error.message);
        if (updateLoadingState && isMountedRef.current) {
          setLoading(false);
        }
        return false;
      }
      
      if (!session) {
        console.log('[Auth] No active session found');
        if (updateLoadingState && isMountedRef.current) {
          setLoading(false);
        }
        return false;
      }
      
      console.log('[Auth] Session verified:', session.user.email);
      sessionVerifiedRef.current = true;
      
      // Update state if session was found but not set
      if (!user && isMountedRef.current) {
        setSession(session);
        setUser(session.user);
        sessionVerifiedRef.current = true;
      } else if (updateLoadingState && isMountedRef.current) {
        setLoading(false);
      }
      
      return true;
    } catch (error) {
      console.error('[Auth] Session verification error:', error);
      if (updateLoadingState && isMountedRef.current) {
        setLoading(false);
      }
      return false;
    }
  };

  // Keep loading state ref in sync
  useEffect(() => {
    loadingStateRef.current = loading;
    console.log('[Auth] Loading state changed:', loading);
  }, [loading]);

  useEffect(() => {
    console.log('[Auth] Initializing auth provider');
    
    // CRITICAL: Set up listener FIRST to catch all events
    const {
      data: { subscription },
    } = supabase.auth.onAuthStateChange((event, session) => {
      console.log('[Auth] State change:', event, 'User:', session?.user?.email || 'none', 'Has session:', !!session);
      
      // Extract email info early for cleanup
      const currentEmail = session?.user?.email;
      const newEmailPending = session?.user?.new_email;
      
      // CRITICAL: Always clear/update pending email state BEFORE any early returns
      setPendingEmail(newEmailPending ?? null);
      
      // Clear any error
      setSessionError(null);
      
      // Update session and user state based on event
      if (event === 'SIGNED_IN' && session) {
        console.log('[Auth] SIGNED_IN detected, setting session and user');
        setSession(session);
        setUser(session.user);
        sessionVerifiedRef.current = true;
      } else if (event === 'INITIAL_SESSION') {
        if (session?.user) {
          console.log('[Auth] INITIAL_SESSION with user, setting session');
          setSession(session);
          setUser(session.user);
          sessionVerifiedRef.current = true;
        } else {
          console.log('[Auth] INITIAL_SESSION with no user - setting loading to false');
          setSession(null);
          setUser(null);
          setProfile(null);
          sessionVerifiedRef.current = false;
          // CRITICAL: Set loading to false immediately when no session
          setLoading(false);
          return; // Exit early, no need to fetch profile
        }
      } else if (event === 'SIGNED_OUT') {
        console.log('[Auth] SIGNED_OUT detected, clearing all state');
        setSession(null);
        setUser(null);
        setProfile(null);
        sessionVerifiedRef.current = false;
        setLoading(false);
        return; // Exit early, no need to fetch profile
      } else {
        setSession(session);
        setUser(session?.user ?? null);
      }
      
      // Detect confirmed email change: email changed AND no longer pending
      if (
        session?.user &&
        previousEmailRef.current &&
        currentEmail &&
        currentEmail !== previousEmailRef.current &&
        !newEmailPending
      ) {
        // Clear any existing Novu update timeout
        if (novuUpdateTimeoutRef.current) {
          clearTimeout(novuUpdateTimeoutRef.current);
        }
        
        // Defer Novu update and notifications to avoid blocking auth
        const oldEmail = previousEmailRef.current;
        novuUpdateTimeoutRef.current = setTimeout(async () => {
          try {
            // Update Novu subscriber with confirmed email
            const { notificationService } = await import('@/lib/notificationService');
            if (notificationService.isEnabled()) {
              await notificationService.updateSubscriber({
                subscriberId: session.user.id,
                email: currentEmail,
              });
            }

            // Log the confirmed email change
            await supabase.from('admin_audit_log').insert({
              admin_user_id: session.user.id,
              target_user_id: session.user.id,
              action: 'email_change_completed',
              details: {
                old_email: oldEmail,
                new_email: currentEmail,
                timestamp: new Date().toISOString(),
              },
            });

            // Send final security notification
            if (notificationService.isEnabled()) {
              await notificationService.trigger({
                workflowId: 'email-changed',
                subscriberId: session.user.id,
                payload: {
                  oldEmail: oldEmail,
                  newEmail: currentEmail,
                  timestamp: new Date().toISOString(),
                },
              });
            }
          } catch (error) {
            console.error('Error updating Novu after email confirmation:', error);
          } finally {
            novuUpdateTimeoutRef.current = null;
          }
        }, 0);
      }
      
      // Update tracked email
      if (currentEmail) {
        previousEmailRef.current = currentEmail;
      }
      
      // Handle profile fetching for authenticated users
      if (session?.user) {
        // Clear any existing profile fetch timeout
        if (profileFetchTimeoutRef.current) {
          clearTimeout(profileFetchTimeoutRef.current);
        }
        
        // Only wait for profile on initial auth events
        const shouldWaitForProfile = (event === 'SIGNED_IN' || event === 'INITIAL_SESSION');
        console.log('[Auth] Fetching profile, shouldWaitForProfile:', shouldWaitForProfile);
        
        profileFetchTimeoutRef.current = setTimeout(() => {
          fetchProfile(session.user.id, 0, () => {
            if (shouldWaitForProfile) {
              console.log('[Auth] Profile fetch complete, setting loading to false');
              setLoading(false);
            }
          });
          profileFetchTimeoutRef.current = null;
        }, 0);
      } else {
        // No session/user - clear profile and resolve loading
        setProfile(null);
        console.log('[Auth] No user, setting loading to false');
        setLoading(false);
      }
    });

    // THEN get initial session (this may trigger INITIAL_SESSION event)
    supabase.auth.getSession().then(({ data: { session }, error }) => {
      if (error) {
        console.error('[Auth] Initial session fetch error:', error);
        setSessionError(error.message);
        setLoading(false);
        return;
      }
      
      // Note: onAuthStateChange will handle the INITIAL_SESSION event
      // This is just a backup in case the event doesn't fire
      console.log('[Auth] getSession completed, session exists:', !!session);
    });

    // Add a STRONG safety timeout to force loading to resolve
    loadingTimeoutRef.current = setTimeout(() => {
      if (loadingStateRef.current) {
        console.warn('[Auth] ⚠️ SAFETY TIMEOUT: Forcing loading to false after 3 seconds');
        setLoading(false);
      }
    }, 3000);

    // Session verification fallback
    const verificationTimeout = setTimeout(() => {
      if (!sessionVerifiedRef.current) {
        console.log('[Auth] Session not verified after 2s, attempting manual verification');
        verifySession();
      }
    }, 2000);

    // Handle page visibility changes
    const handleVisibilityChange = () => {
      if (document.visibilityState === 'visible') {
        console.log('[Auth] Tab became visible, verifying session');
        verifySession();
      }
    };
    
    document.addEventListener('visibilitychange', handleVisibilityChange);

    return () => {
      console.log('[Auth] Cleaning up auth provider');
      isMountedRef.current = false;
      subscription.unsubscribe();
      clearTimeout(verificationTimeout);
      if (loadingTimeoutRef.current) {
        clearTimeout(loadingTimeoutRef.current);
      }
      document.removeEventListener('visibilitychange', handleVisibilityChange);
      
      // Clear any pending timeouts
      if (profileFetchTimeoutRef.current) {
        clearTimeout(profileFetchTimeoutRef.current);
        profileFetchTimeoutRef.current = null;
      }
      if (novuUpdateTimeoutRef.current) {
        clearTimeout(novuUpdateTimeoutRef.current);
        novuUpdateTimeoutRef.current = null;
      }
    };
  }, []);

  const signOut = async () => {
    const { error } = await supabase.auth.signOut();
    if (error) {
      console.error('Error signing out:', error);
      throw error;
    }
  };

  const clearPendingEmail = () => {
    setPendingEmail(null);
  };

  const value = {
    user,
    session,
    profile,
    loading,
    pendingEmail,
    sessionError,
    signOut,
    refreshProfile,
    verifySession,
    clearPendingEmail,
  };

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

export const AuthProvider = AuthProviderComponent;

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