// src/providers/AuthProvider.tsx
import React, { useState, useEffect, useCallback, ReactNode } from 'react';
import { AuthContext, AuthContextType } from '../contexts/AuthContext';
import type { User, UserProfile } from '../types';
import * as apiClient from '../services/apiClient';
import { useApi } from '../hooks/useApi';
import { logger } from '../services/logger.client';

export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
  const [user, setUser] = useState<User | null>(null);
  const [profile, setProfile] = useState<UserProfile | null>(null);
  const [authStatus, setAuthStatus] = useState<AuthContextType['authStatus']>('Determining...');
  const [isLoading, setIsLoading] = useState(true);
  const { execute: checkTokenApi } = useApi<UserProfile, []>(
    () => apiClient.getAuthenticatedUserProfile()
  );
  const { execute: fetchProfileApi } = useApi<UserProfile, []>(
    () => apiClient.getAuthenticatedUserProfile()
  );

  useEffect(() => {
    // This flag prevents state updates if the component unmounts or if another
    // auth operation (like login/logout) occurs before this initial check completes.
    let isMounted = true;

    const checkAuthToken = async () => {
      const token = localStorage.getItem('authToken');
      if (token) {
        logger.info('Found auth token in local storage. Validating...');
        try {
          const userProfile = await checkTokenApi();
          if (isMounted && userProfile) {
            setUser(userProfile.user);
            setProfile(userProfile);
            setAuthStatus('AUTHENTICATED');
            logger.info('Token validated successfully.', { user: userProfile.user });
          } else if (isMounted) { // This case handles if checkTokenApi returns null due to an error
            localStorage.removeItem('authToken');
            setUser(null);
            setProfile(null);
            setAuthStatus('SIGNED_OUT');
          }
        } catch (e) {
          // This catch block is now primarily for unexpected errors, as useApi handles API errors.
          logger.warn('Auth token validation failed. Clearing token.', { error: e });
          if (isMounted) {
            localStorage.removeItem('authToken');
            setUser(null);
            setProfile(null);
            setAuthStatus('SIGNED_OUT');
          }
        }
      } else {
        logger.info('No auth token found. User is signed out.');
        if (isMounted) {
          setAuthStatus('SIGNED_OUT');
        }
      }

      if (isMounted) {
        setIsLoading(false);
      }
    };

    checkAuthToken();

    return () => { isMounted = false; };
  }, [checkTokenApi]);

  const logout = useCallback(() => {
    localStorage.removeItem('authToken');
    setUser(null);
    setProfile(null);
    setAuthStatus('SIGNED_OUT');
  }, []);

  const login = useCallback(async (loggedInUser: User, token: string) => {
    localStorage.setItem('authToken', token);
    try {
      const userProfile = await fetchProfileApi();
      setUser(userProfile!.user);
      setProfile(userProfile);
      setAuthStatus('AUTHENTICATED');
      logger.info('Login and data fetch successful', { user: loggedInUser });
    } catch (e) {
      const errorMessage = e instanceof Error ? e.message : String(e);
      logger.error('Failed to fetch user data after login. Rolling back auth state.', { error: errorMessage });
      logout(); // Log the user out to prevent an inconsistent state.
      // Re-throw the error so the calling component can handle it (e.g., show a notification)
      throw new Error(`Login succeeded, but failed to fetch your data: ${errorMessage}`);
    }
  }, [fetchProfileApi, logout]);

  const updateProfile = useCallback((updatedProfileData: Partial<UserProfile>) => {
    setProfile(prevProfile => {
      if (!prevProfile) return null;
      return { ...prevProfile, ...updatedProfileData };
    });
  }, []);

  const value = { user, profile, authStatus, isLoading, login, logout, updateProfile };

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