import { Injectable, inject } from '@angular/core';
import { HubUsersService } from '@modules/hub-users-management/hub-users.service';
import { MerchantUsersService } from '@modules/hub-users-management/merchant-users.service';
import { BehaviorSubject, Observable, map, tap, of, catchError } from 'rxjs';
import { UserRole, UserType, AvailableRole } from '@core/models/dcb-bo-hub-user.model';

export interface RolePermission {
  canCreateUsers: boolean;
  canEditUsers: boolean;
  canDeleteUsers: boolean;
  canManageRoles: boolean;
  canViewStats: boolean;
  canManageMerchants: boolean;
  canAccessAdmin: boolean;
  canAccessSupport: boolean;
  canAccessPartner: boolean;
  assignableRoles: UserRole[];
}

export interface AvailableRolesWithPermissions {
  roles: (AvailableRole & { permissions: RolePermission })[];
}

@Injectable({
  providedIn: 'root'
})
export class RoleManagementService {
  private hubUsersService = inject(HubUsersService);
  private merchantUsersService = inject(MerchantUsersService);
  
  private availableRoles$ = new BehaviorSubject<AvailableRolesWithPermissions | null>(null);
  private currentUserRole$ = new BehaviorSubject<UserRole | null>(null);

  /**
   * Charge les rôles Hub disponibles
   */
  loadAvailableHubRoles(): Observable<AvailableRolesWithPermissions> {
    return this.hubUsersService.getAvailableHubRoles().pipe(
      map(apiResponse => ({
        roles: apiResponse.roles.map(role => ({
          ...role,
          permissions: this.getPermissionsForRole(role.value)
        }))
      })),
      tap(roles => this.availableRoles$.next(roles)),
      catchError(error => this.getDefaultHubRoles(error))
    );
  }

  /**
   * Charge les rôles Marchands disponibles
   */
  loadAvailableMerchantRoles(): Observable<AvailableRolesWithPermissions> {
    return this.merchantUsersService.getAvailableMerchantRoles().pipe(
      map(apiResponse => ({
        roles: apiResponse.roles.map(role => ({
          ...role,
          permissions: this.getPermissionsForRole(role.value)
        }))
      })),
      tap(roles => this.availableRoles$.next(roles)),
      catchError(error => this.getDefaultMerchantRoles(error))
    );
  }

  /**
   * Rôles Hub par défaut en cas d'erreur
   */
  private getDefaultHubRoles(error?: any): Observable<AvailableRolesWithPermissions> {
    console.error('Error loading hub roles:', error);
    const defaultRoles: AvailableRolesWithPermissions = {
      roles: [
        UserRole.DCB_ADMIN, 
        UserRole.DCB_SUPPORT, 
        UserRole.DCB_PARTNER
      ].map(role => ({
        value: role,
        label: this.getRoleLabel(role),
        description: this.getRoleDescription(role),
        allowedForCreation: true,
        userType: UserType.HUB,
        permissions: this.getPermissionsForRole(role)
      }))
    };
    this.availableRoles$.next(defaultRoles);
    return of(defaultRoles);
  }

  /**
   * Rôles Marchands par défaut en cas d'erreur
   */
  private getDefaultMerchantRoles(error?: any): Observable<AvailableRolesWithPermissions> {
    console.error('Error loading merchant roles:', error);
    const defaultRoles: AvailableRolesWithPermissions = {
      roles: [
        UserRole.DCB_PARTNER_ADMIN, 
        UserRole.DCB_PARTNER_MANAGER, 
        UserRole.DCB_PARTNER_SUPPORT
      ].map(role => ({
        value: role,
        label: this.getRoleLabel(role),
        description: this.getRoleDescription(role),
        allowedForCreation: true,
        userType: UserType.MERCHANT_PARTNER,
        permissions: this.getPermissionsForRole(role)
      }))
    };
    this.availableRoles$.next(defaultRoles);
    return of(defaultRoles);
  }

  /**
   * Définit le rôle de l'utilisateur courant
   */
  setCurrentUserRole(role: UserRole): void {
    this.currentUserRole$.next(role);
  }

  /**
   * Récupère le rôle de l'utilisateur courant
   */
  getCurrentUserRole(): Observable<UserRole | null> {
    return this.currentUserRole$.asObservable();
  }

  /**
   * Récupère la valeur actuelle du rôle utilisateur (synchrone)
   */
  getCurrentUserRoleValue(): UserRole | null {
    return this.currentUserRole$.value;
  }

  /**
   * Récupère les permissions détaillées selon le rôle
   */
  getPermissionsForRole(role: UserRole | null): RolePermission {
    if (!role) {
      return this.getDefaultPermissions();
    }

    const allRoles = this.getAllRoles();
    const hubRoles = [UserRole.DCB_SUPPORT, UserRole.DCB_PARTNER, UserRole.DCB_PARTNER_ADMIN, UserRole.DCB_PARTNER_MANAGER, UserRole.DCB_PARTNER_SUPPORT];
    const merchantRoles = [UserRole.DCB_PARTNER_ADMIN, UserRole.DCB_PARTNER_MANAGER, UserRole.DCB_PARTNER_SUPPORT];

    switch (role) {
      case UserRole.DCB_ADMIN:
        return {
          canCreateUsers: true,
          canEditUsers: true,
          canDeleteUsers: true,
          canManageRoles: true,
          canViewStats: true,
          canManageMerchants: true,
          canAccessAdmin: true,
          canAccessSupport: true,
          canAccessPartner: true,
          assignableRoles: allRoles
        };
      
      case UserRole.DCB_SUPPORT:
        return {
          canCreateUsers: true,
          canEditUsers: true,
          canDeleteUsers: false,
          canManageRoles: true,
          canViewStats: true,
          canManageMerchants: true,
          canAccessAdmin: false,
          canAccessSupport: true,
          canAccessPartner: true,
          assignableRoles: hubRoles,
        };
      
      case UserRole.DCB_PARTNER:
        return {
          canCreateUsers: true,
          canEditUsers: true,
          canDeleteUsers: true,
          canManageRoles: true,
          canViewStats: true,
          canManageMerchants: false,
          canAccessAdmin: false,
          canAccessSupport: false,
          canAccessPartner: false,
          assignableRoles: merchantRoles
        };
      
      case UserRole.DCB_PARTNER_ADMIN:
        return {
          canCreateUsers: true,
          canEditUsers: true,
          canDeleteUsers: true,
          canManageRoles: true,
          canViewStats: true,
          canManageMerchants: true,
          canAccessAdmin: false,
          canAccessSupport: false,
          canAccessPartner: true,
          assignableRoles: [UserRole.DCB_PARTNER_MANAGER, UserRole.DCB_PARTNER_SUPPORT]
        };
      
      case UserRole.DCB_PARTNER_MANAGER:
        return {
          canCreateUsers: false,
          canEditUsers: false,
          canDeleteUsers: false,
          canManageRoles: false,
          canViewStats: true,
          canManageMerchants: true,
          canAccessAdmin: false,
          canAccessSupport: false,
          canAccessPartner: true,
          assignableRoles: []
        };
      
      case UserRole.DCB_PARTNER_SUPPORT:
        return {
          canCreateUsers: false,
          canEditUsers: false,
          canDeleteUsers: false,
          canManageRoles: false,
          canViewStats: true,
          canManageMerchants: false,
          canAccessAdmin: false,
          canAccessSupport: false,
          canAccessPartner: true,
          assignableRoles: []
        };
      
      default:
        return this.getDefaultPermissions();
    }
  }

  /**
   * Permissions par défaut (rôle inconnu ou non défini)
   */
  private getDefaultPermissions(): RolePermission {
    return {
      canCreateUsers: false,
      canEditUsers: false,
      canDeleteUsers: false,
      canManageRoles: false,
      canViewStats: false,
      canManageMerchants: false,
      canAccessAdmin: false,
      canAccessSupport: false,
      canAccessPartner: false,
      assignableRoles: []
    };
  }

  /**
   * Vérifie si un rôle peut être attribué par l'utilisateur courant
   */
  canAssignRole(currentUserRole: UserRole | null, targetRole: UserRole): boolean {
    if (!currentUserRole) return false;

    // Rôles qui peuvent attribuer tous les rôles
    const fullPermissionRoles = [
      UserRole.DCB_ADMIN, 
      UserRole.DCB_SUPPORT, 
      UserRole.DCB_PARTNER
    ];

    if (fullPermissionRoles.includes(currentUserRole)) {
      return true;
    }
    
    // Pour les autres rôles, utiliser les permissions définies
    const permissions = this.getPermissionsForRole(currentUserRole);
    return permissions.assignableRoles.includes(targetRole);
  }

  /**
   * Vérifie si l'utilisateur courant peut créer des utilisateurs
   */
  canCreateUsers(currentUserRole: UserRole | null): boolean {
    return currentUserRole ? this.getPermissionsForRole(currentUserRole).canCreateUsers : false;
  }

  /**
   * Vérifie si l'utilisateur courant peut éditer des utilisateurs
   */
  canEditUsers(currentUserRole: UserRole | null): boolean {
    return currentUserRole ? this.getPermissionsForRole(currentUserRole).canEditUsers : false;
  }

  /**
   * Vérifie si l'utilisateur courant peut supprimer des utilisateurs
   */
  canDeleteUsers(currentUserRole: UserRole | null): boolean {
    return currentUserRole ? this.getPermissionsForRole(currentUserRole).canDeleteUsers : false;
  }

  /**
   * Vérifie si l'utilisateur courant peut gérer les rôles
   */
  canManageRoles(currentUserRole: UserRole | null): boolean {
    return currentUserRole ? this.getPermissionsForRole(currentUserRole).canManageRoles : false;
  }

  /**
   * Vérifie si l'utilisateur courant peut accéder aux statistiques
   */
  canViewStats(currentUserRole: UserRole | null): boolean {
    return currentUserRole ? this.getPermissionsForRole(currentUserRole).canViewStats : false;
  }

  /**
   * Vérifie si l'utilisateur courant peut gérer les merchants
   */
  canManageMerchants(currentUserRole: UserRole | null): boolean {
    return currentUserRole ? this.getPermissionsForRole(currentUserRole).canManageMerchants : false;
  }

  /**
   * Vérifie si l'utilisateur courant peut accéder à l'admin
   */
  canAccessAdmin(currentUserRole: UserRole | null): boolean {
    return currentUserRole ? this.getPermissionsForRole(currentUserRole).canAccessAdmin : false;
  }

  /**
   * Vérifie si l'utilisateur courant peut accéder au support
   */
  canAccessSupport(currentUserRole: UserRole | null): boolean {
    return currentUserRole ? this.getPermissionsForRole(currentUserRole).canAccessSupport : false;
  }

  /**
   * Vérifie si l'utilisateur courant peut accéder à l'espace partenaire
   */
  canAccessPartner(currentUserRole: UserRole | null): boolean {
    return currentUserRole ? this.getPermissionsForRole(currentUserRole).canAccessPartner : false;
  }

  /**
   * Récupère le libellé d'un rôle
   */
  getRoleLabel(role: string): string {
    const userRole = role as UserRole;
    switch (userRole) {
      case UserRole.DCB_ADMIN:
        return 'Administrateur DCB';
      case UserRole.DCB_SUPPORT:
        return 'Support DCB';
      case UserRole.DCB_PARTNER:
        return 'Partenaire DCB';
      case UserRole.DCB_PARTNER_ADMIN:
        return 'Admin Partenaire';
      case UserRole.DCB_PARTNER_MANAGER:
        return 'Manager Partenaire';
      case UserRole.DCB_PARTNER_SUPPORT:
        return 'Support Partenaire';
      default:
        return role;
    }
  }

  /**
   * Récupère la description d'un rôle
   */
  getRoleDescription(role: string | UserRole): string {
    const userRole = role as UserRole;
    const roleDescriptions: { [key in UserRole]: string } = {
      [UserRole.DCB_ADMIN]: 'Administrateur système avec tous les accès',
      [UserRole.DCB_SUPPORT]: 'Support technique avec accès étendus',
      [UserRole.DCB_PARTNER]: 'Partenaire commercial principal',
      [UserRole.DCB_PARTNER_ADMIN]: 'Administrateur de partenaire marchand',
      [UserRole.DCB_PARTNER_MANAGER]: 'Manager opérationnel partenaire',
      [UserRole.DCB_PARTNER_SUPPORT]: 'Support technique partenaire'
    };
    return roleDescriptions[userRole] || 'Description non disponible';
  }

  /**
   * Récupère la classe CSS pour un badge de rôle
   */
  getRoleBadgeClass(role: string): string {
    const userRole = role as UserRole;
    switch (userRole) {
      case UserRole.DCB_ADMIN:
        return 'bg-danger';
      case UserRole.DCB_SUPPORT:
        return 'bg-info';
      case UserRole.DCB_PARTNER:
        return 'bg-primary';
      case UserRole.DCB_PARTNER_ADMIN:
        return 'bg-warning';
      case UserRole.DCB_PARTNER_MANAGER:
        return 'bg-success';
      case UserRole.DCB_PARTNER_SUPPORT:
        return 'bg-secondary';
      default:
        return 'bg-secondary';
    }
  }

  /**
   * Récupère l'icône pour un rôle
   */
  getRoleIcon(role: string): string {
    const userRole = role as UserRole;
    switch (userRole) {
      case UserRole.DCB_ADMIN:
        return 'lucideShield';
      case UserRole.DCB_SUPPORT:
        return 'lucideHeadphones';
      case UserRole.DCB_PARTNER:
        return 'lucideBuilding';
      case UserRole.DCB_PARTNER_ADMIN:
        return 'lucideShieldCheck';
      case UserRole.DCB_PARTNER_MANAGER:
        return 'lucideUserCog';
      case UserRole.DCB_PARTNER_SUPPORT:
        return 'lucideHeadphones';
      default:
        return 'lucideUser';
    }
  }


  /**
   * Vérifie si un rôle est un rôle administrateur
   */
  isAdminRole(role: UserRole): boolean {
    return role === UserRole.DCB_ADMIN;
  }

  /**
   * Vérifie si un rôle est un rôle support
   */
  isSupportRole(role: UserRole): boolean {
    return role === UserRole.DCB_SUPPORT;
  }

  /**
   * Vérifie si un rôle est un rôle partenaire
   */
  isPartnerRole(role: UserRole): boolean {
    return role === UserRole.DCB_PARTNER;
  }

  /**
   * Vérifie si un rôle est un rôle marchand
   */
  isMerchantRole(role: UserRole): boolean {
    const merchantRoles = [
      UserRole.DCB_PARTNER_ADMIN, 
      UserRole.DCB_PARTNER_MANAGER, 
      UserRole.DCB_PARTNER_SUPPORT
    ];
    return merchantRoles.includes(role);
  }

  /**
   * Récupère tous les rôles disponibles sous forme de tableau
   */
  getAllRoles(): UserRole[] {
    return Object.values(UserRole);
  }

  /**
   * Récupère les rôles que l'utilisateur courant peut attribuer
   */
  getAssignableRoles(currentUserRole: UserRole | null): UserRole[] {
    if (!currentUserRole) return [];
    return this.getPermissionsForRole(currentUserRole).assignableRoles;
  }

  /**
   * Récupère les rôles Hub assignables (pour le composant unifié)
   */
  getAssignableHubRoles(currentUserRole: UserRole | null): UserRole[] {
    if (!currentUserRole) return [];
    
    const allHubRoles = this.getHubRoles();
    const permissions = this.getPermissionsForRole(currentUserRole);
    
    return allHubRoles.filter(role => 
      permissions.assignableRoles.includes(role)
    );
  }

  /**
   * Récupère les rôles Marchands assignables (pour le composant unifié)
   */
  getAssignableMerchantRoles(currentUserRole: UserRole | null): UserRole[] {
    if (!currentUserRole) return [];
    
    const allMerchantRoles = this.getMerchantRoles();
    const permissions = this.getPermissionsForRole(currentUserRole);
    
    return allMerchantRoles.filter(role => 
      permissions.assignableRoles.includes(role)
    );
  }

  /**
   * Récupère uniquement les rôles Hub
   */
  getHubRoles(): UserRole[] {
    return [
      UserRole.DCB_ADMIN, 
      UserRole.DCB_SUPPORT, 
      UserRole.DCB_PARTNER
    ];
  }

  /**
   * Récupère uniquement les rôles Marchands
   */
  getMerchantRoles(): UserRole[] {
    return [
      UserRole.DCB_PARTNER_ADMIN, 
      UserRole.DCB_PARTNER_MANAGER, 
      UserRole.DCB_PARTNER_SUPPORT
    ];
  }

  /**
   * Vérifie si l'utilisateur a un rôle spécifique
   */
  hasRole(userRole: UserRole | null, targetRole: UserRole): boolean {
    return userRole === targetRole;
  }

  /**
   * Vérifie si l'utilisateur a au moins un des rôles spécifiés
   */
  hasAnyRole(userRole: UserRole | null, targetRoles: UserRole[]): boolean {
    return userRole ? targetRoles.includes(userRole) : false;
  }

  /**
   * Réinitialise le cache des rôles
   */
  clearCache(): void {
    this.availableRoles$.next(null);
    this.currentUserRole$.next(null);
  }

  /**
   * Récupère les rôles disponibles (observable)
   */
  getAvailableRoles(): Observable<AvailableRolesWithPermissions | null> {
    return this.availableRoles$.asObservable();
  }
}