
import React, { createContext, useEffect, useState } from 'react';
import { supabase } from '@/integrations/supabase/client';
import { useToast } from '@/hooks/use-toast';

interface AuthUser {
  id: string;
  email: string;
  full_name?: string;
  avatar_url?: string;
  phone_number?: string;
  status_message?: string | null;
  status_updated_at?: string | null;
}

interface AuthSession {
  access_token: string;
  refresh_token: string;
  expires_at: string;
}

interface AuthError {
  message: string;
  code?: string;
}

interface ProfileUpdateData {
  full_name?: string;
  avatar_url?: string;
  phone_number?: string;
}

export interface AuthContextType {
  user: AuthUser | null;
  session: AuthSession | null;
  loading: boolean;
  isAdmin: boolean;
  signUp: (email: string, password: string, fullName: string, dob: string, phoneNumber: string) => Promise<{ user: AuthUser | null; session: AuthSession | null; error: AuthError | null }>;
  signIn: (email: string, password: string) => Promise<{ error: AuthError | null }>;
  signOut: () => Promise<{ error: AuthError | null }>;
  resetPassword: (email: string) => Promise<{ error: AuthError | null }>;
  resendConfirmationEmail: (email: string) => Promise<{ error: AuthError | null }>;
  updateProfile: (data: ProfileUpdateData) => Promise<{ error: AuthError | null }>;
  refreshUserData: () => Promise<void>;
}

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

export { AuthContext };

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const initializeRef = React.useRef(false);
  
  const [user, setUser] = useState<AuthUser | null>(null);
  const [session, setSession] = useState<AuthSession | null>(null);
  const [loading, setLoading] = useState(true);
  const [isAdmin, setIsAdmin] = useState(false);
  const { toast } = useToast();

  // Prevent duplicate initializations
  if (!initializeRef.current) {
    console.log('AuthProvider initializing...');
    initializeRef.current = true;
  }

  useEffect(() => {
    // Get initial session
    supabase.auth.getSession().then(async ({ data: { session } }) => {
      setSession(session as any);
      
      if (session?.user) {
        try {
          // Fetch full profile data including avatar_url
          const { data: profileData } = await supabase
            .from('profiles')
            .select('id, email, full_name, avatar_url, phone_number, role, status_message, status_updated_at')
            .eq('id', session.user.id)
            .single();
          
          if (profileData) {
            // Merge auth user data with profile data
            const fullUser: AuthUser = {
              id: session.user.id,
              email: session.user.email || profileData.email,
              full_name: profileData.full_name || session.user.user_metadata?.full_name,
              avatar_url: profileData.avatar_url || undefined,
              phone_number: profileData.phone_number || session.user.user_metadata?.phone_number,
              status_message: profileData.status_message || null,
              status_updated_at: profileData.status_updated_at || null,
            };
            setUser(fullUser);
          } else {
            // Fallback to basic auth user data
            setUser(session.user as any);
          }
        } catch (error) {
          console.error('Error fetching profile data:', error);
          // Fallback to basic auth user data on error
          setUser(session.user as any);
        }
      } else {
        setUser(null);
      }
      
      setLoading(false);
    }).catch((error) => {
      console.error('Error getting session:', error);
      setLoading(false);
    });

    // Listen for auth changes
    const {
      data: { subscription },
    } = supabase.auth.onAuthStateChange((event, session) => {
      console.log('Auth state changed:', event, session?.user?.email);
      setSession(session as any);
      
      if (session?.user) {
        // Use setTimeout to defer profile fetching and prevent deadlock
        setTimeout(async () => {
          try {
            // Fetch full profile data including avatar_url
            const { data: profileData } = await supabase
              .from('profiles')
              .select('id, email, full_name, avatar_url, phone_number, role, status_message, status_updated_at')
              .eq('id', session.user.id)
              .single();
            
            if (profileData) {
              // Merge auth user data with profile data
              const fullUser: AuthUser = {
                id: session.user.id,
                email: session.user.email || profileData.email,
                full_name: profileData.full_name || session.user.user_metadata?.full_name,
                avatar_url: profileData.avatar_url || undefined,
                phone_number: profileData.phone_number || session.user.user_metadata?.phone_number,
                status_message: profileData.status_message || null,
                status_updated_at: profileData.status_updated_at || null,
              };
              setUser(fullUser);
            } else {
              // Fallback to basic auth user data
              setUser(session.user as any);
            }
          } catch (error) {
            console.error('Error fetching profile data in auth change:', error);
            // Fallback to basic auth user data on error
            setUser(session.user as any);
          }
        }, 0);
      } else {
        setUser(null);
      }
      
      setLoading(false);
      
      // If session is restored, refresh it to ensure it's valid
      if (session && event === 'TOKEN_REFRESHED') {
        console.log('Session refreshed, re-checking admin status');
        // Trigger admin status check using setTimeout to prevent deadlock
        setTimeout(async () => {
          try {
            const { data: profileData } = await supabase
              .from('profiles')
              .select('role')
              .eq('id', session.user.id)
              .single();
            
            if (profileData) {
              setIsAdmin(profileData.role === 'admin');
            }
          } catch (error) {
            console.error('Error checking admin role on token refresh:', error);
          }
        }, 0);
      }
    });

    return () => subscription.unsubscribe();
  }, []);

  // Check admin status when user changes
  useEffect(() => {
    const checkAdminStatus = async () => {
      if (user) {
        try {
          console.log('Checking admin status for user:', user.email);
          // Use the is_user_admin function instead of querying profiles directly
          const { data, error } = await supabase.rpc('is_user_admin', {
            user_id: user.id
          });

          if (error) {
            console.error('Error checking admin status:', error);
            // Don't immediately set isAdmin to false on error
            // Instead, try to get the session again to see if it's still valid
            const { data: sessionData } = await supabase.auth.getSession();
            if (sessionData.session) {
              // Session is still valid, keep current admin status
              console.log('Session still valid, keeping current admin status');
            } else {
              console.log('Session invalid, setting admin to false');
              setIsAdmin(false);
            }
          } else {
            const newAdminStatus = data || false;
            console.log('Admin status updated:', newAdminStatus);
            setIsAdmin(newAdminStatus);
          }
        } catch (error) {
          console.error('Exception checking admin status:', error);
          // On exception, check if session is still valid
          const { data: sessionData } = await supabase.auth.getSession();
          if (!sessionData.session) {
            setIsAdmin(false);
          }
          // If session is valid, keep current admin status
        }
      } else {
        console.log('No user, setting admin to false');
        setIsAdmin(false);
      }
    };

    checkAdminStatus();
    
    // Set up periodic session check for admin users
    if (user) {
      const interval = setInterval(async () => {
        const { data: sessionData } = await supabase.auth.getSession();
        if (!sessionData.session) {
          console.log('Session expired during periodic check');
          setIsAdmin(false);
        }
      }, 5 * 60 * 1000); // Check every 5 minutes
      
      return () => clearInterval(interval);
    }
  }, [user]);

  const signUp = async (email: string, password: string, fullName: string, dob: string, phoneNumber: string) => {
    try {
      // Process metadata with all provided information
      const processedMetadata = {
        full_name: fullName.trim(),
        date_of_birth: dob,
        phone_number: phoneNumber ? phoneNumber.replace(/\D/g, '') : undefined
      };

      console.log('SignUp - Full Name:', fullName);
      console.log('SignUp - Date of Birth:', dob);
      console.log('SignUp - Original phone:', phoneNumber);
      console.log('SignUp - Processed metadata:', processedMetadata);

      const { data, error } = await supabase.auth.signUp({
        email,
        password,
        options: {
          emailRedirectTo: `${window.location.origin}/`,
          data: processedMetadata,
        },
      });

      if (error) {
        toast({
          title: "Sign Up Failed",
          description: error.message,
          variant: "destructive",
        });
      } else if (data.user && !data.session) {
        toast({
          title: "Check Your Email",
          description: "We've sent you a confirmation link.",
        });
        
        // Send welcome email and create in-app notification
        try {
          await supabase.functions.invoke('send-welcome-email', {
            body: {
              email: data.user.email,
              fullName: fullName,
              redirect_to: `${window.location.origin}/`,
              userId: data.user.id
            }
          });
        } catch (welcomeError) {
          console.error('Error sending welcome message:', welcomeError);
        }
      } else if (data.user && data.session) {
        // User is immediately confirmed, send welcome message
        try {
          await supabase.functions.invoke('send-welcome-email', {
            body: {
              email: data.user.email,
              fullName: fullName,
              redirect_to: `${window.location.origin}/`,
              userId: data.user.id
            }
          });
        } catch (welcomeError) {
          console.error('Error sending welcome message:', welcomeError);
        }
      }

      return { user: data.user as AuthUser | null, session: data.session as AuthSession | null, error: error as AuthError | null };
    } catch (error: unknown) {
      const authError = error as AuthError;
      toast({
        title: "Sign Up Failed",
        description: authError.message,
        variant: "destructive",
      });
      return { user: null, session: null, error: authError as AuthError | null };
    }
  };

  const signIn = async (email: string, password: string) => {
    try {
      const { error } = await supabase.auth.signInWithPassword({
        email,
        password,
      });

      if (error) {
        toast({
          title: "Sign In Failed",
          description: error.message,
          variant: "destructive",
        });
      } else {
        toast({
          title: "Welcome back!",
          description: "You have successfully signed in.",
        });
      }

      return { error: error as AuthError | null };
    } catch (error: unknown) {
      const authError = error as AuthError;
      toast({
        title: "Sign In Failed",
        description: authError.message,
        variant: "destructive",
      });
      return { error: authError as AuthError | null };
    }
  };

  const signOut = async () => {
    try {
      const { error } = await supabase.auth.signOut();
      
      if (error) {
        toast({
          title: "Sign Out Failed",
          description: error.message,
          variant: "destructive",
        });
      } else {
        toast({
          title: "Signed Out",
          description: "You have been successfully signed out.",
        });
      }

      return { error: error as AuthError | null };
    } catch (error: unknown) {
      const authError = error as AuthError;
      toast({
        title: "Sign Out Failed",
        description: authError.message,
        variant: "destructive",
      });
      return { error: authError as AuthError | null };
    }
  };

  const resetPassword = async (email: string) => {
    try {
      const { error } = await supabase.auth.resetPasswordForEmail(email, {
        redirectTo: `${window.location.origin}/reset-password`,
      });

      if (error) {
        toast({
          title: "Reset Failed",
          description: error.message,
          variant: "destructive",
        });
      } else {
        toast({
          title: "Reset Email Sent",
          description: "Check your email for reset instructions.",
        });
      }

      return { error: error as AuthError | null };
    } catch (error: unknown) {
      const authError = error as AuthError;
      toast({
        title: "Reset Failed",
        description: authError.message,
        variant: "destructive",
      });
      return { error: authError as AuthError | null };
    }
  };

  const resendConfirmationEmail = async (email: string) => {
    try {
      const { error } = await supabase.auth.resend({
        type: 'signup',
        email: email,
        options: {
          emailRedirectTo: `${window.location.origin}/`
        }
      });

      if (error) {
        toast({
          title: "Resend Failed",
          description: error.message,
          variant: "destructive",
        });
      } else {
        toast({
          title: "Confirmation Email Sent",
          description: "Please check your email for the confirmation link.",
        });
      }

      return { error: error as AuthError | null };
    } catch (error: unknown) {
      const authError = error as AuthError;
      toast({
        title: "Resend Failed",
        description: authError.message,
        variant: "destructive",
      });
      return { error: authError as AuthError | null };
    }
  };

  const updateProfile = async (data: ProfileUpdateData) => {
    try {
      if (!user) throw new Error('No user logged in');

      // Convert phone number to string format if provided
      const processedData: ProfileUpdateData = {
        ...data,
        phone_number: data.phone_number ? String(data.phone_number).replace(/\D/g, '') : undefined,
      };

      console.log('UpdateProfile called with:', {
        original: data,
        processed: processedData,
        userId: user.id,
      });

      const { error } = await supabase
        .from('profiles')
        .update(processedData)
        .eq('id', user.id);

      if (error) {
        console.error('Profile update error:', error);
        toast({
          title: 'Update Failed',
          description: error.message,
          variant: 'destructive',
        });
        return { error: error as AuthError | null };
      }

      // Also keep Supabase Auth user metadata in sync (for display_name etc.)
      try {
        const metadata: Record<string, string> = {};
        if (processedData.full_name) {
          metadata.full_name = processedData.full_name;
        }
        if (processedData.phone_number) {
          metadata.phone_number = processedData.phone_number;
        }

        if (Object.keys(metadata).length > 0) {
          const { error: metadataError } = await supabase.auth.updateUser({
            data: metadata,
          });
          if (metadataError) {
            console.warn('Non-blocking metadata update error:', metadataError);
          }
        }
      } catch (metaError) {
        console.warn('Exception while updating auth metadata (non-blocking):', metaError);
      }

      console.log('Profile update successful, refetching data...');

      // Refresh user data to reflect the updated profile
      const { data: updatedProfileData, error: fetchError } = await supabase
        .from('profiles')
        .select('id, email, full_name, avatar_url, phone_number, role, status_message, status_updated_at')
        .eq('id', user.id)
        .single();

      console.log('Refetched profile data:', {
        data: updatedProfileData,
        error: fetchError,
      });

      if (fetchError) {
        console.error('Error refetching profile:', fetchError);
      }

      if (updatedProfileData) {
        const fullUser: AuthUser = {
          id: user.id,
          email: user.email,
          full_name: updatedProfileData.full_name,
          avatar_url: updatedProfileData.avatar_url || undefined,
          phone_number: updatedProfileData.phone_number || user.phone_number,
          status_message: updatedProfileData.status_message || null,
          status_updated_at: updatedProfileData.status_updated_at || null,
        };

        console.log('Setting user state to:', fullUser);
        setUser(fullUser);

        toast({
          title: 'Profile Updated',
          description: 'Your profile has been successfully updated.',
        });
      }

      return { error: null };
    } catch (error: unknown) {
      const authError = error as AuthError;
      console.error('Exception in updateProfile:', authError);
      toast({
        title: 'Update Failed',
        description: authError.message,
        variant: 'destructive',
      });
      return { error: authError as AuthError | null };
    }
  };

  const refreshUserData = async () => {
    if (!user?.id) return;
    
    try {
      const { data: profileData } = await supabase
        .from('profiles')
        .select('id, email, full_name, avatar_url, phone_number, role, status_message, status_updated_at')
        .eq('id', user.id)
        .single();
      
      if (profileData) {
        const fullUser: AuthUser = {
          id: user.id,
          email: user.email,
          full_name: profileData.full_name || user.full_name,
          avatar_url: profileData.avatar_url || undefined,
          phone_number: profileData.phone_number || user.phone_number,
          status_message: profileData.status_message || null,
          status_updated_at: profileData.status_updated_at || null,
        };
        setUser(fullUser);
      }
    } catch (error) {
      console.error('Error refreshing user data:', error);
    }
  };

  const value = {
    user,
    session,
    loading,
    isAdmin,
    signUp,
    signIn,
    signOut,
    resetPassword,
    resendConfirmationEmail,
    updateProfile,
    refreshUserData,
  };

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

