/// BLoC d'authentification Keycloak adaptatif avec gestion des rôles
/// Support Keycloak avec contextes multi-organisations et états sophistiqués
library auth_bloc;

import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart';
import '../models/user.dart';
import '../models/user_role.dart';
import '../services/permission_engine.dart';
import '../services/keycloak_auth_service.dart';
import '../../cache/dashboard_cache_manager.dart';

// === ÉVÉNEMENTS ===

/// Événements d'authentification
abstract class AuthEvent extends Equatable {
  const AuthEvent();
  
  @override
  List<Object?> get props => [];
}

/// Événement de connexion Keycloak
class AuthLoginRequested extends AuthEvent {
  const AuthLoginRequested();
}

/// Événement de déconnexion
class AuthLogoutRequested extends AuthEvent {
  const AuthLogoutRequested();
}

/// Événement de changement de contexte organisationnel
class AuthOrganizationContextChanged extends AuthEvent {
  final String organizationId;
  
  const AuthOrganizationContextChanged(this.organizationId);
  
  @override
  List<Object?> get props => [organizationId];
}

/// Événement de rafraîchissement du token
class AuthTokenRefreshRequested extends AuthEvent {
  const AuthTokenRefreshRequested();
}

/// Événement de vérification de l'état d'authentification
class AuthStatusChecked extends AuthEvent {
  const AuthStatusChecked();
}

/// Événement de mise à jour du profil utilisateur
class AuthUserProfileUpdated extends AuthEvent {
  final User updatedUser;

  const AuthUserProfileUpdated(this.updatedUser);

  @override
  List<Object?> get props => [updatedUser];
}

/// Événement de callback WebView
class AuthWebViewCallback extends AuthEvent {
  final String callbackUrl;
  final User? user;

  const AuthWebViewCallback(this.callbackUrl, {this.user});

  @override
  List<Object?> get props => [callbackUrl, user];
}

// === ÉTATS ===

/// États d'authentification
abstract class AuthState extends Equatable {
  const AuthState();
  
  @override
  List<Object?> get props => [];
}

/// État initial
class AuthInitial extends AuthState {
  const AuthInitial();
}

/// État de chargement
class AuthLoading extends AuthState {
  const AuthLoading();
}

/// État authentifié avec contexte riche
class AuthAuthenticated extends AuthState {
  final User user;
  final String? currentOrganizationId;
  final UserRole effectiveRole;
  final List<String> effectivePermissions;
  final DateTime authenticatedAt;
  final String? accessToken;
  
  const AuthAuthenticated({
    required this.user,
    this.currentOrganizationId,
    required this.effectiveRole,
    required this.effectivePermissions,
    required this.authenticatedAt,
    this.accessToken,
  });
  
  /// Vérifie si l'utilisateur a une permission
  bool hasPermission(String permission) {
    return effectivePermissions.contains(permission);
  }
  
  /// Vérifie si l'utilisateur peut effectuer une action
  bool canPerformAction(String domain, String action, {String scope = 'own'}) {
    final permission = '$domain.$action.$scope';
    return hasPermission(permission);
  }
  
  /// Obtient le contexte organisationnel actuel
  UserOrganizationContext? get currentOrganizationContext {
    if (currentOrganizationId == null) return null;
    return user.getOrganizationContext(currentOrganizationId!);
  }
  
  /// Crée une copie avec des modifications
  AuthAuthenticated copyWith({
    User? user,
    String? currentOrganizationId,
    UserRole? effectiveRole,
    List<String>? effectivePermissions,
    DateTime? authenticatedAt,
    String? accessToken,
  }) {
    return AuthAuthenticated(
      user: user ?? this.user,
      currentOrganizationId: currentOrganizationId ?? this.currentOrganizationId,
      effectiveRole: effectiveRole ?? this.effectiveRole,
      effectivePermissions: effectivePermissions ?? this.effectivePermissions,
      authenticatedAt: authenticatedAt ?? this.authenticatedAt,
      accessToken: accessToken ?? this.accessToken,
    );
  }
  
  @override
  List<Object?> get props => [
    user,
    currentOrganizationId,
    effectiveRole,
    effectivePermissions,
    authenticatedAt,
    accessToken,
  ];
}

/// État non authentifié
class AuthUnauthenticated extends AuthState {
  final String? message;
  
  const AuthUnauthenticated({this.message});
  
  @override
  List<Object?> get props => [message];
}

/// État d'erreur
class AuthError extends AuthState {
  final String message;
  final String? errorCode;
  
  const AuthError({
    required this.message,
    this.errorCode,
  });
  
  @override
  List<Object?> get props => [message, errorCode];
}

/// État indiquant qu'une WebView d'authentification est requise
class AuthWebViewRequired extends AuthState {
  final String authUrl;
  final String state;
  final String codeVerifier;

  const AuthWebViewRequired({
    required this.authUrl,
    required this.state,
    required this.codeVerifier,
  });

  @override
  List<Object?> get props => [authUrl, state, codeVerifier];
}

// === BLOC ===

/// BLoC d'authentification adaptatif
class AuthBloc extends Bloc<AuthEvent, AuthState> {
  AuthBloc() : super(const AuthInitial()) {
    on<AuthLoginRequested>(_onLoginRequested);
    on<AuthLogoutRequested>(_onLogoutRequested);
    on<AuthOrganizationContextChanged>(_onOrganizationContextChanged);
    on<AuthTokenRefreshRequested>(_onTokenRefreshRequested);
    on<AuthStatusChecked>(_onStatusChecked);
    on<AuthUserProfileUpdated>(_onUserProfileUpdated);
    on<AuthWebViewCallback>(_onWebViewCallback);
  }

  /// Gère la demande de connexion Keycloak via WebView
  ///
  /// Cette méthode prépare l'authentification WebView et émet un état spécial
  /// pour indiquer qu'une WebView doit être ouverte
  Future<void> _onLoginRequested(
    AuthLoginRequested event,
    Emitter<AuthState> emit,
  ) async {
    emit(const AuthLoading());

    try {
      debugPrint('🔐 Préparation authentification Keycloak WebView...');

      // Préparer l'authentification WebView
      final Map<String, String> authParams = await KeycloakAuthService.prepareWebViewAuthentication();

      debugPrint('✅ Authentification WebView préparée');

      // Émettre un état spécial pour indiquer qu'une WebView doit être ouverte
      debugPrint('🚀 Émission de l\'état AuthWebViewRequired...');
      emit(AuthWebViewRequired(
        authUrl: authParams['url']!,
        state: authParams['state']!,
        codeVerifier: authParams['code_verifier']!,
      ));
      debugPrint('✅ État AuthWebViewRequired émis');

    } catch (e, stackTrace) {
      debugPrint('💥 Erreur préparation authentification Keycloak: $e');
      debugPrint('Stack trace: $stackTrace');
      emit(AuthError(message: 'Erreur de préparation: $e'));
    }
  }

  /// Traite le callback WebView et finalise l'authentification
  Future<void> _onWebViewCallback(
    AuthWebViewCallback event,
    Emitter<AuthState> emit,
  ) async {
    emit(const AuthLoading());

    try {
      debugPrint('🔄 Traitement callback WebView...');

      // Utiliser l'utilisateur fourni ou traiter le callback
      final User user;
      if (event.user != null) {
        debugPrint('👤 Utilisation des données utilisateur fournies: ${event.user!.fullName}');
        user = event.user!;
      } else {
        debugPrint('🔄 Traitement du callback URL: ${event.callbackUrl}');
        user = await KeycloakAuthService.handleWebViewCallback(event.callbackUrl);
      }

      debugPrint('👤 Utilisateur authentifié: ${user.fullName} (${user.primaryRole.displayName})');

      // Calculer les permissions effectives
      debugPrint('🔐 Calcul des permissions effectives...');
      final effectivePermissions = await PermissionEngine.getEffectivePermissions(user);
      debugPrint('✅ Permissions effectives calculées: ${effectivePermissions.length} permissions');

      // Invalider le cache pour forcer le rechargement
      debugPrint('🧹 Invalidation du cache pour le rôle ${user.primaryRole.displayName}...');
      await DashboardCacheManager.invalidateForRole(user.primaryRole);
      debugPrint('✅ Cache invalidé');

      emit(AuthAuthenticated(
        user: user,
        currentOrganizationId: null, // À implémenter selon vos besoins
        effectiveRole: user.primaryRole,
        effectivePermissions: effectivePermissions,
        authenticatedAt: DateTime.now(),
        accessToken: '', // Token géré par KeycloakWebViewAuthService
      ));

      debugPrint('🎉 Authentification complète réussie - navigation vers dashboard');

    } catch (e, stackTrace) {
      debugPrint('💥 Erreur authentification: $e');
      debugPrint('Stack trace: $stackTrace');
      emit(AuthError(message: 'Erreur de connexion: $e'));
    }
  }

  /// Gère la demande de déconnexion Keycloak
  Future<void> _onLogoutRequested(
    AuthLogoutRequested event,
    Emitter<AuthState> emit,
  ) async {
    emit(const AuthLoading());

    try {
      debugPrint('🚪 Démarrage déconnexion Keycloak...');

      // Déconnexion Keycloak
      final logoutSuccess = await KeycloakAuthService.logout();

      if (!logoutSuccess) {
        debugPrint('⚠️ Déconnexion Keycloak partielle');
      }

      // Nettoyer le cache local
      await DashboardCacheManager.clear();

      // Invalider le cache des permissions
      if (state is AuthAuthenticated) {
        final authState = state as AuthAuthenticated;
        PermissionEngine.invalidateUserCache(authState.user.id);
      }

      debugPrint('✅ Déconnexion complète réussie');
      emit(const AuthUnauthenticated(message: 'Déconnexion réussie'));

    } catch (e, stackTrace) {
      debugPrint('💥 Erreur déconnexion: $e');
      debugPrint('Stack trace: $stackTrace');
      emit(AuthError(message: 'Erreur de déconnexion: $e'));
    }
  }

  /// Gère le changement de contexte organisationnel
  Future<void> _onOrganizationContextChanged(
    AuthOrganizationContextChanged event,
    Emitter<AuthState> emit,
  ) async {
    if (state is! AuthAuthenticated) return;
    
    final currentState = state as AuthAuthenticated;
    emit(const AuthLoading());
    
    try {
      // Recalculer le rôle effectif et les permissions
      final effectiveRole = currentState.user.getRoleInOrganization(event.organizationId);
      
      final effectivePermissions = await PermissionEngine.getEffectivePermissions(
        currentState.user,
        organizationId: event.organizationId,
      );
      
      // Invalider le cache pour le nouveau contexte
      PermissionEngine.invalidateUserCache(currentState.user.id);
      
      emit(currentState.copyWith(
        currentOrganizationId: event.organizationId,
        effectiveRole: effectiveRole,
        effectivePermissions: effectivePermissions,
      ));
      
    } catch (e) {
      emit(AuthError(message: 'Erreur de changement de contexte: $e'));
    }
  }

  /// Gère le rafraîchissement du token
  Future<void> _onTokenRefreshRequested(
    AuthTokenRefreshRequested event,
    Emitter<AuthState> emit,
  ) async {
    if (state is! AuthAuthenticated) return;
    
    final currentState = state as AuthAuthenticated;
    
    try {
      // Simulation du rafraîchissement (à remplacer par l'API réelle)
      await Future.delayed(const Duration(seconds: 1));
      
      final newToken = 'refreshed_token_${DateTime.now().millisecondsSinceEpoch}';
      
      emit(currentState.copyWith(accessToken: newToken));
      
    } catch (e) {
      emit(AuthError(message: 'Erreur de rafraîchissement: $e'));
    }
  }

  /// Vérifie l'état d'authentification Keycloak
  Future<void> _onStatusChecked(
    AuthStatusChecked event,
    Emitter<AuthState> emit,
  ) async {
    emit(const AuthLoading());

    try {
      debugPrint('🔍 Vérification état authentification Keycloak...');

      // Vérifier si l'utilisateur est authentifié avec Keycloak
      final bool isAuthenticated = await KeycloakAuthService.isAuthenticated();

      if (!isAuthenticated) {
        debugPrint('❌ Utilisateur non authentifié');
        emit(const AuthUnauthenticated());
        return;
      }

      // Récupérer l'utilisateur actuel
      final User? user = await KeycloakAuthService.getCurrentUser();

      if (user == null) {
        debugPrint('❌ Impossible de récupérer l\'utilisateur');
        emit(const AuthUnauthenticated());
        return;
      }

      // Calculer les permissions effectives
      final effectivePermissions = await PermissionEngine.getEffectivePermissions(user);

      // Récupérer le token d'accès
      final String? accessToken = await KeycloakAuthService.getAccessToken();

      debugPrint('✅ Utilisateur authentifié: ${user.fullName}');

      emit(AuthAuthenticated(
        user: user,
        currentOrganizationId: null, // À implémenter selon vos besoins
        effectiveRole: user.primaryRole,
        effectivePermissions: effectivePermissions,
        authenticatedAt: DateTime.now(),
        accessToken: accessToken ?? '',
      ));

    } catch (e, stackTrace) {
      debugPrint('💥 Erreur vérification authentification: $e');
      debugPrint('Stack trace: $stackTrace');
      emit(AuthError(message: 'Erreur de vérification: $e'));
    }
  }

  /// Met à jour le profil utilisateur
  Future<void> _onUserProfileUpdated(
    AuthUserProfileUpdated event,
    Emitter<AuthState> emit,
  ) async {
    if (state is! AuthAuthenticated) return;
    
    final currentState = state as AuthAuthenticated;
    
    try {
      // Recalculer les permissions si nécessaire
      final effectivePermissions = await PermissionEngine.getEffectivePermissions(
        event.updatedUser,
        organizationId: currentState.currentOrganizationId,
      );
      
      emit(currentState.copyWith(
        user: event.updatedUser,
        effectivePermissions: effectivePermissions,
      ));
      
    } catch (e) {
      emit(AuthError(message: 'Erreur de mise à jour: $e'));
    }
  }


}
