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 fetchProfile = async (userId: string, retryCount = 0) => {
    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);
            }
          }, delay);
          return;
        }
        
        // Show user-friendly error notification only after all retries
        if (isMountedRef.current && retryCount >= 3) {
          toast({
            title: "Profile Loading Error",
            description: "Unable to load your profile. Please refresh the page or try again later.",
            variant: "destructive",
          });
        }
        return;
      }

      // Only update state if component is still mounted
      if (isMountedRef.current) {
        setProfile(data as Profile);
        profileRetryCountRef.current = 0; // Reset retry count on success
      }
    } 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);
          }
        }, delay);
      }
    }
  };

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

  // Verify session is still valid
  const verifySession = async () => {
    try {
      const { data: { session }, error } = await supabase.auth.getSession();
      
      if (error) {
        console.error('[Auth] Session verification failed:', error);
        setSessionError(error.message);
        return false;
      }
      
      if (!session) {
        console.log('[Auth] No active session found');
        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);
        fetchProfile(session.user.id);
      }
      
      return true;
    } catch (error) {
      console.error('[Auth] Session verification error:', error);
      return false;
    }
  };

  useEffect(() => {
    // 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');
      
      if (!isMountedRef.current) return;
      
      const currentEmail = session?.user?.email;
      const newEmailPending = session?.user?.new_email;
      
      // Clear any error
      setSessionError(null);
      
      // Explicitly handle SIGNED_IN event for iframe compatibility
      if (event === 'SIGNED_IN' && session) {
        console.log('[Auth] SIGNED_IN detected, setting session and user');
        setSession(session);
        setUser(session.user);
        sessionVerifiedRef.current = true;
        setLoading(false);
      } else if (event === 'SIGNED_OUT') {
        console.log('[Auth] SIGNED_OUT detected, clearing session');
        setSession(null);
        setUser(null);
        setProfile(null);
        sessionVerifiedRef.current = false;
      } else {
        setSession(session);
        setUser(session?.user ?? null);
      }
      
      // Track pending email changes
      setPendingEmail(newEmailPending ?? 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 () => {
          if (!isMountedRef.current) return;
          
          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;
      }
      
      if (session?.user) {
        // Clear any existing profile fetch timeout
        if (profileFetchTimeoutRef.current) {
          clearTimeout(profileFetchTimeoutRef.current);
        }
        
        // Defer profile fetch to avoid deadlock
        profileFetchTimeoutRef.current = setTimeout(() => {
          if (!isMountedRef.current) return;
          fetchProfile(session.user.id);
          profileFetchTimeoutRef.current = null;
        }, 0);
      } else {
        if (isMountedRef.current) {
          setProfile(null);
        }
      }
      
      setLoading(false);
    });

    // THEN get initial session
    supabase.auth.getSession().then(({ data: { session }, error }) => {
      if (!isMountedRef.current) return;
      
      if (error) {
        console.error('[Auth] Initial session fetch error:', error);
        setSessionError(error.message);
      }
      
      setSession(session);
      setUser(session?.user ?? null);
      if (session?.user) {
        fetchProfile(session.user.id);
        sessionVerifiedRef.current = true;
      }
      setLoading(false);
    });

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

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

    return () => {
      isMountedRef.current = false;
      subscription.unsubscribe();
      clearTimeout(verificationTimeout);
      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;
}