'use client';

import React, { createContext, useContext, useEffect, useState, useCallback } from 'react';
import { AuthUser, AuthState, AuthConfig } from '../types';
import { getAuthInstance, initAuth } from '../services/auth.service';

interface AuthContextValue extends AuthState {
  signIn: (email: string, password: string, rememberMe?: boolean) => Promise<AuthUser>;
  signUp: (email: string, password: string, displayName?: string) => Promise<AuthUser>;
  signOut: () => Promise<void>;
  signInWithProvider: (provider: 'google' | 'github') => Promise<AuthUser>;
  sendPasswordResetEmail: (email: string) => Promise<void>;
  refreshUser: () => Promise<void>;
}

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

interface AuthProviderProps {
  children: React.ReactNode;
  config?: AuthConfig;
}

export function AuthProvider({ children, config }: AuthProviderProps) {
  const [state, setState] = useState<AuthState>({
    user: null,
    loading: true,
    error: null,
    isAuthenticated: false,
  });

  // Initialize auth service if config provided
  useEffect(() => {
    if (config) {
      initAuth(config);
    }
  }, [config]);

  // Subscribe to auth state changes
  useEffect(() => {
    try {
      const auth = getAuthInstance();
      
      const unsubscribe = auth.onAuthStateChange((user) => {
        setState({
          user,
          loading: false,
          error: null,
          isAuthenticated: !!user,
        });
      });

      return unsubscribe;
    } catch (error) {
      setState({
        user: null,
        loading: false,
        error: {
          code: 'auth/not-initialized',
          message: 'Auth not initialized. Provide config to AuthProvider.',
        },
        isAuthenticated: false,
      });
      return () => {}; // Return empty cleanup function
    }
  }, []);

  const signIn = useCallback(async (email: string, password: string, rememberMe = false) => {
    setState(prev => ({ ...prev, loading: true, error: null }));
    
    try {
      const auth = getAuthInstance();
      const { user } = await auth.signIn({ email, password, rememberMe });
      
      setState({
        user,
        loading: false,
        error: null,
        isAuthenticated: true,
      });
      
      return user;
    } catch (error: any) {
      setState(prev => ({
        ...prev,
        loading: false,
        error,
      }));
      throw error;
    }
  }, []);

  const signUp = useCallback(async (email: string, password: string, displayName?: string) => {
    setState(prev => ({ ...prev, loading: true, error: null }));
    
    try {
      const auth = getAuthInstance();
      const { user } = await auth.signUp({ email, password, displayName });
      
      setState({
        user,
        loading: false,
        error: null,
        isAuthenticated: true,
      });
      
      return user;
    } catch (error: any) {
      setState(prev => ({
        ...prev,
        loading: false,
        error,
      }));
      throw error;
    }
  }, []);

  const signOut = useCallback(async () => {
    setState(prev => ({ ...prev, loading: true, error: null }));
    
    try {
      const auth = getAuthInstance();
      await auth.signOut();
      
      setState({
        user: null,
        loading: false,
        error: null,
        isAuthenticated: false,
      });
    } catch (error: any) {
      setState(prev => ({
        ...prev,
        loading: false,
        error,
      }));
      throw error;
    }
  }, []);

  const signInWithProvider = useCallback(async (provider: 'google' | 'github') => {
    setState(prev => ({ ...prev, loading: true, error: null }));
    
    try {
      const auth = getAuthInstance();
      const { user } = await auth.signInWith(provider);
      
      setState({
        user,
        loading: false,
        error: null,
        isAuthenticated: true,
      });
      
      return user;
    } catch (error: any) {
      setState(prev => ({
        ...prev,
        loading: false,
        error,
      }));
      throw error;
    }
  }, []);

  const sendPasswordResetEmail = useCallback(async (email: string) => {
    try {
      const auth = getAuthInstance();
      await auth.sendPasswordResetEmail(email);
    } catch (error: any) {
      setState(prev => ({
        ...prev,
        error,
      }));
      throw error;
    }
  }, []);

  const refreshUser = useCallback(async () => {
    if (!state.user) return;
    
    setState(prev => ({ ...prev, loading: true }));
    
    try {
      // Force token refresh to get latest custom claims
      await state.user.getIdToken(true);
      const auth = getAuthInstance();
      const currentUser = auth.getCurrentUser();
      
      setState(prev => ({
        ...prev,
        user: currentUser,
        loading: false,
      }));
    } catch (error: any) {
      setState(prev => ({
        ...prev,
        loading: false,
        error,
      }));
    }
  }, [state.user]);

  const value: AuthContextValue = {
    ...state,
    signIn,
    signUp,
    signOut,
    signInWithProvider,
    sendPasswordResetEmail,
    refreshUser,
  };

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

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