'use client';

import React, { createContext, useContext, useEffect, useState, useCallback, ReactNode } from 'react';
import { initKeycloak, keycloakInitOptions, RoleUtils, BTP_ROLES, KEYCLOAK_TIMEOUTS, KEYCLOAK_REDIRECTS } from '@/config/keycloak';
import { useRouter } from 'next/navigation';

// Types pour l'authentification
export interface UserInfo {
  id: string;
  username: string;
  email: string;
  firstName?: string;
  lastName?: string;
  fullName?: string;
  roles: string[];
  permissions: string[];
  highestRole?: string;
  isAdmin: boolean;
  isManager: boolean;
  isEmployee: boolean;
  isClient: boolean;
}

export interface AuthState {
  isAuthenticated: boolean;
  isLoading: boolean;
  user: UserInfo | null;
  token: string | null;
  refreshToken: string | null;
  error: string | null;
}

export interface AuthContextType extends AuthState {
  login: () => Promise<void>;
  logout: () => Promise<void>;
  refreshAuth: () => Promise<void>;
  hasRole: (role: string) => boolean;
  hasAnyRole: (roles: string[]) => boolean;
  hasPermission: (permission: string) => boolean;
  isRoleHigher: (role: string) => boolean;
  updateToken: (minValidity?: number) => Promise<boolean>;
}

// Contexte d'authentification
const AuthContext = createContext<AuthContextType | undefined>(undefined);

// Hook pour utiliser le contexte d'authentification
export const useAuth = (): AuthContextType => {
  const context = useContext(AuthContext);
  if (!context) {
    throw new Error('useAuth must be used within an AuthProvider');
  }
  return context;
};

// Props du provider
interface AuthProviderProps {
  children: ReactNode;
}

// Provider d'authentification
export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
  const router = useRouter();
  
  // État de l'authentification
  const [authState, setAuthState] = useState<AuthState>({
    isAuthenticated: false,
    isLoading: true,
    user: null,
    token: null,
    refreshToken: null,
    error: null,
  });

  // Fonction pour récupérer les informations utilisateur depuis l'API
  const fetchUserInfo = useCallback(async (token: string): Promise<UserInfo | null> => {
    try {
      const response = await fetch('/api/v1/auth/user', {
        method: 'GET',
        headers: {
          'Authorization': `Bearer ${token}`,
          'Content-Type': 'application/json',
        },
      });

      if (!response.ok) {
        console.warn('Impossible de récupérer les informations utilisateur depuis l\'API');
        return null;
      }

      const userData = await response.json();

      // Convertir les données de l'API vers le format UserInfo
      const userInfo: UserInfo = {
        id: userData.id,
        username: userData.username,
        email: userData.email,
        firstName: userData.firstName,
        lastName: userData.lastName,
        fullName: userData.fullName,
        roles: userData.roles || [],
        permissions: userData.permissions || [],
        highestRole: userData.roles?.[0] || undefined,
        isAdmin: userData.isAdmin || false,
        isManager: userData.isManager || false,
        isEmployee: userData.isEmployee || false,
        isClient: userData.isClient || false,
      };

      return userInfo;
    } catch (error) {
      console.error('Erreur lors de la récupération des informations utilisateur:', error);
      return null;
    }
  }, []);

  // Fonction pour extraire les informations utilisateur (fallback)
  const extractUserInfo = useCallback((keycloakInstance: any): UserInfo | null => {
    if (!keycloakInstance.tokenParsed) return null;

    const tokenParsed = keycloakInstance.tokenParsed;
    const realmAccess = keycloakInstance.realmAccess || {};
    const resourceAccess = keycloakInstance.resourceAccess || {};

    // Extraction des rôles
    const realmRoles = realmAccess.roles || [];
    const clientRoles = resourceAccess['btpxpress-frontend']?.roles || [];
    const allRoles = [...realmRoles, ...clientRoles];

    // Informations utilisateur
    const userInfo: UserInfo = {
      id: tokenParsed.sub,
      username: tokenParsed.preferred_username || tokenParsed.email,
      email: tokenParsed.email,
      firstName: tokenParsed.given_name,
      lastName: tokenParsed.family_name,
      fullName: tokenParsed.name || `${tokenParsed.given_name || ''} ${tokenParsed.family_name || ''}`.trim(),
      roles: allRoles,
      permissions: RoleUtils.getUserPermissions(allRoles),
      highestRole: RoleUtils.getHighestRole(allRoles) || undefined,
      isAdmin: RoleUtils.hasAnyRole(allRoles, [BTP_ROLES.SUPER_ADMIN, BTP_ROLES.ADMIN]),
      isManager: RoleUtils.hasAnyRole(allRoles, [BTP_ROLES.DIRECTEUR, BTP_ROLES.MANAGER, BTP_ROLES.CHEF_CHANTIER]),
      isEmployee: RoleUtils.hasAnyRole(allRoles, [BTP_ROLES.EMPLOYE, BTP_ROLES.OUVRIER, BTP_ROLES.CHEF_EQUIPE]),
      isClient: RoleUtils.hasAnyRole(allRoles, [BTP_ROLES.CLIENT_ENTREPRISE, BTP_ROLES.CLIENT_PARTICULIER]),
    };

    return userInfo;
  }, []);

  // Fonction pour mettre à jour l'état d'authentification
  const updateAuthState = useCallback(async (keycloakInstance: any) => {
    if (keycloakInstance && keycloakInstance.authenticated) {
      // Essayer d'abord de récupérer les informations depuis l'API
      let user = await fetchUserInfo(keycloakInstance.token);

      // Si l'API ne répond pas, utiliser les informations du token JWT
      if (!user) {
        user = extractUserInfo(keycloakInstance);
      }

      setAuthState({
        isAuthenticated: true,
        isLoading: false,
        user,
        token: keycloakInstance.token,
        refreshToken: keycloakInstance.refreshToken,
        error: null,
      });
    } else {
      setAuthState({
        isAuthenticated: false,
        isLoading: false,
        user: null,
        token: null,
        refreshToken: null,
        error: null,
      });
    }
  }, [fetchUserInfo, extractUserInfo]);

  // Fonction de connexion
  const login = useCallback(async (): Promise<void> => {
    try {
      // Redirection directe vers l'API d'authentification
      window.location.href = '/api/auth/login';
    } catch (error) {
      console.error('Erreur lors de la connexion:', error);
      setAuthState(prev => ({
        ...prev,
        error: 'Erreur lors de la connexion',
        isLoading: false,
      }));
    }
  }, []);

  // Fonction de déconnexion
  const logout = useCallback(async (): Promise<void> => {
    try {
      // Nettoyer les tokens locaux
      localStorage.removeItem('accessToken');
      localStorage.removeItem('refreshToken');
      localStorage.removeItem('idToken');

      // Supprimer le cookie
      document.cookie = 'keycloak-token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT';

      // Redirection directe vers l'API de déconnexion
      window.location.href = '/api/auth/logout';
    } catch (error) {
      console.error('Erreur lors de la déconnexion:', error);
      // Forcer la déconnexion locale même en cas d'erreur
      setAuthState({
        isAuthenticated: false,
        isLoading: false,
        user: null,
        token: null,
        refreshToken: null,
        error: null,
      });
      router.push('/');
    }
  }, [router]);

  // Fonction pour rafraîchir l'authentification
  const refreshAuth = useCallback(async (): Promise<void> => {
    try {
      // Vérifier les tokens stockés
      const accessToken = localStorage.getItem('accessToken');
      const refreshToken = localStorage.getItem('refreshToken');

      if (!refreshToken) {
        await logout();
        return;
      }

      // TODO: Implémenter le rafraîchissement via API si nécessaire
      console.log('Rafraîchissement des tokens...');

    } catch (error) {
      console.error('Erreur lors du rafraîchissement du token:', error);
      await logout();
    }
  }, [logout]);

  // Fonction pour mettre à jour le token
  const updateToken = useCallback(async (minValidity: number = 30): Promise<boolean> => {
    try {
      // Vérifier si le token est encore valide
      const accessToken = localStorage.getItem('accessToken');
      if (!accessToken) {
        return false;
      }

      // TODO: Vérifier l'expiration du token et rafraîchir si nécessaire
      return true;
    } catch (error) {
      console.error('Erreur lors de la mise à jour du token:', error);
      return false;
    }
  }, []);

  // Fonctions utilitaires pour les rôles et permissions
  const hasRole = useCallback((role: string): boolean => {
    return authState.user ? RoleUtils.hasRole(authState.user.roles, role) : false;
  }, [authState.user]);

  const hasAnyRole = useCallback((roles: string[]): boolean => {
    return authState.user ? RoleUtils.hasAnyRole(authState.user.roles, roles) : false;
  }, [authState.user]);

  const hasPermission = useCallback((permission: string): boolean => {
    return authState.user ? RoleUtils.hasPermission(authState.user.roles, permission) : false;
  }, [authState.user]);

  const isRoleHigher = useCallback((role: string): boolean => {
    if (!authState.user?.highestRole) return false;
    return RoleUtils.isRoleHigher(authState.user.highestRole, role);
  }, [authState.user]);

  // Initialisation de Keycloak - Désactivée pour utiliser l'authentification manuelle
  useEffect(() => {
    const initializeKeycloak = async () => {
      try {
        // Vérifier s'il y a des tokens stockés localement
        const accessToken = localStorage.getItem('accessToken');
        const refreshToken = localStorage.getItem('refreshToken');
        const idToken = localStorage.getItem('idToken');

        if (accessToken) {
          // Stocker aussi dans un cookie pour le middleware
          document.cookie = `keycloak-token=${accessToken}; path=/; max-age=3600; SameSite=Lax`;

          // Récupérer les informations utilisateur depuis l'API
          try {
            const user = await fetchUserInfo(accessToken);

            if (user) {
              setAuthState({
                isAuthenticated: true,
                isLoading: false,
                user,
                token: accessToken,
                refreshToken: refreshToken,
                error: null,
              });
              return;
            }
          } catch (error) {
            console.warn('Impossible de récupérer les informations utilisateur depuis l\'API, utilisation des données par défaut');
          }

          // Fallback avec des données par défaut si l'API ne répond pas
          setAuthState({
            isAuthenticated: true,
            isLoading: false,
            user: {
              id: 'dev-user-001',
              username: 'admin.btpxpress',
              email: 'admin@btpxpress.com',
              firstName: 'Jean-Michel',
              lastName: 'Martineau',
              fullName: 'Jean-Michel Martineau',
              roles: [BTP_ROLES.SUPER_ADMIN, BTP_ROLES.ADMIN, BTP_ROLES.DIRECTEUR],
              permissions: RoleUtils.getUserPermissions([BTP_ROLES.SUPER_ADMIN]),
              highestRole: BTP_ROLES.SUPER_ADMIN,
              isAdmin: true,
              isManager: true,
              isEmployee: false,
              isClient: false,
            },
            token: accessToken,
            refreshToken: refreshToken,
            error: null,
          });
          return;
        }

        // Pas de tokens, rester non authentifié
        setAuthState({
          isAuthenticated: false,
          isLoading: false,
          user: null,
          token: null,
          refreshToken: null,
          error: null,
        });

      } catch (error) {
        console.error('Erreur lors de l\'initialisation de l\'authentification:', error);
        setAuthState({
          isAuthenticated: false,
          isLoading: false,
          user: null,
          token: null,
          refreshToken: null,
          error: 'Erreur lors de l\'initialisation de l\'authentification',
        });
      }
    };

    initializeKeycloak();
  }, [updateAuthState, refreshAuth, logout]);

  // Rafraîchissement automatique du token
  useEffect(() => {
    if (!authState.isAuthenticated) return;

    const interval = setInterval(() => {
      updateToken();
    }, KEYCLOAK_TIMEOUTS.SESSION_CHECK_INTERVAL * 1000);

    return () => clearInterval(interval);
  }, [authState.isAuthenticated, updateToken]);

  // Valeur du contexte
  const contextValue: AuthContextType = {
    ...authState,
    login,
    logout,
    refreshAuth,
    hasRole,
    hasAnyRole,
    hasPermission,
    isRoleHigher,
    updateToken,
  };

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

export default AuthProvider;
