import React, { createContext, useContext, ReactNode, useState, useCallback, useEffect } from 'react';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from '../../store/hooks';
import { 
  login, 
  silentLogin as reduxSilentLogin, 
  SignOutResult, 
  getGetConnectedUser,
  getLoginResult,
  setAuthState
} from '../../store/auth/authSlice';
import { authService } from '../../services/Auth-service';
import { RootState } from '../../store';
import { IUser } from '../../store/userProfile/types';
import { Logger } from '../../utils/Log';
import { eventEmitter, EventType } from '../../services/EventEmitter';
import { IAuthResult } from '../../store/auth/types';
import { getAppConfigurationResult, getAppConfiguration } from '../../store/configuration/appConfigSlice';

const logger = new Logger('AuthContext');

// Memoized selector using createSelector
const selectAuthState = createSelector(
  [(state: RootState) => state.authReducer.user],
  (user) => ({
    user,
    isAuthenticated: !!user
  })
);

// Define the shape of the authentication state
export interface AuthState {
  isAuthenticated: boolean;
  user: IUser | null;
  login: (credentials: { email: string; password: string }) => Promise<boolean>;
  logout: () => Promise<void>;
  silentLogin: () => Promise<boolean>;
}

// Create a default implementation with Redux-based methods
export const createDefaultAuthContext = (dispatch: any, authState: { user: any; isAuthenticated: boolean }): AuthState => ({
  isAuthenticated: authState.isAuthenticated,
  user: authState.user,
  login: async (credentials) => {
    try {
      logger.info(`Attempting login ${{ email: credentials.email }}`);
      await dispatch(login(credentials));
      await dispatch(getGetConnectedUser());
      return true;
    } catch (error) {
      logger.error(`Login failed', ${error}`);
      return false;
    }
  },
  logout: async () => {
    await dispatch(SignOutResult());
  },
  silentLogin: async () => {
    try {
      logger.info('Attempting silent login');
      await authService.silentLogin();
      await dispatch(getGetConnectedUser());
      return true;
    } catch (error) {
      logger.error(`Silent login failed, ${error}`);
      return false;
    }
  }
});

const defaultAuthContext: AuthState = {
  isAuthenticated: false,
  user: null,
  login: async () => false,
  logout: async () => {},
  silentLogin: async () => false,
};

const AuthContext = createContext<AuthState>(defaultAuthContext);

// New hook to manage authentication state across components
export const useAuthState = () => {
  const dispatch = useAppDispatch();
  const [isLoading, setIsLoading] = useState(true);
  
  // Selectors
  const storeUser = useAppSelector((state) => state.authReducer.user);
  const isAuthInProgress = useAppSelector((state) => state.authReducer.isAuthInProgress);

  const initializeAuth = useCallback(async () => {
    try {
      // Only attempt silent login if no user exists   
      if (!storeUser ) {
        logger.info('Attempting initial silent login');
        setIsLoading(true);

        await dispatch(reduxSilentLogin());
      }
    } catch (error) {
      logger.error(`Initial auth setup failed: ${error}`);
    } finally {
      setIsLoading(false);
    }
  }, [dispatch, storeUser]);

  const setupAuthListeners = useCallback(() => {
    const AuthStateChangelistener = eventEmitter.addListener(
      EventType.AuthStateChange,
      async (result: { inProgress: boolean , error?: boolean}) => {
        logger.info('Auth State Changed');
        await dispatch(setAuthState(result));
      }
    )
    // Authentication Result Listener
    const  CurrentUserUpdatedListener = eventEmitter.addListener(
      EventType.AuthenticationResult,
      async (result: IAuthResult) => {
        logger.info(`Authentication Result Received', ${result}`);
        
        // Dispatch login result and fetch connected user
        await dispatch(getLoginResult(result));
        await dispatch(getGetConnectedUser());
        
        setIsLoading(false);
      }
    );

    // Sign Out Listener
    const CurrentUserSignedOutListener = eventEmitter.addListener(
      EventType.CurrentUserSignedOut, 
      () => {
        logger.info('User Signed Out');
        dispatch(SignOutResult());
        setIsLoading(false);
      }
    );

    // App Configuration Listener
    const AppConfigurationListener = eventEmitter.addListener(
      EventType.AppConfiguration, 
      (appConfiguration) => {
        dispatch(getAppConfigurationResult(appConfiguration));
      }
    );
    
    // Fetch app configuration
    dispatch(getAppConfiguration());
 
    // Return cleanup function
    return () => {
      logger.info('Auth Listeners Cleanup');
      CurrentUserUpdatedListener.remove();
      CurrentUserSignedOutListener.remove();
      AppConfigurationListener.remove();
      AuthStateChangelistener.remove();
    };
  }, [dispatch]);

  useEffect(() => {
    const cleanup = setupAuthListeners();
    return cleanup;
  }, [setupAuthListeners]);

  useEffect(() => {
    initializeAuth();
  }, [initializeAuth]);

  return {
    isLoading,
    setIsLoading,
    storeUser,
    isAuthInProgress
  };
};

// Provider component that wraps the app and provides authentication state
export const AuthProvider: React.FC<{
  children: ReactNode;
}> = ({ children}) => {
  const dispatch = useAppDispatch();
  
  // Use memoized selector to get auth state
  const { user, isAuthenticated } = useAppSelector(selectAuthState);

  // Create default auth context with Redux methods
  const defaultMethods = createDefaultAuthContext(dispatch, { user, isAuthenticated });

  // Merge default implementation with custom implementation
  const authContextValue: AuthState = {
    ...defaultMethods,
  };

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

// Custom hook to use the auth context
export const useAuth = () => useContext(AuthContext);
