/// Modèles de données utilisateur avec contexte et permissions
/// Support des relations multi-organisations et permissions contextuelles
library user_models;

import 'package:equatable/equatable.dart';
import 'user_role.dart';

/// Modèle utilisateur principal avec contexte multi-organisations
/// 
/// Supporte les utilisateurs ayant des rôles différents dans plusieurs organisations
/// avec des permissions contextuelles et des préférences personnalisées
class User extends Equatable {
  /// Identifiant unique de l'utilisateur
  final String id;
  
  /// Informations personnelles
  final String email;
  final String firstName;
  final String lastName;
  final String? avatar;
  final String? phone;
  
  /// Rôle principal de l'utilisateur (le plus élevé)
  final UserRole primaryRole;
  
  /// Contextes organisationnels (rôles dans différentes organisations)
  final List<UserOrganizationContext> organizationContexts;
  
  /// Permissions supplémentaires accordées spécifiquement
  final List<String> additionalPermissions;
  
  /// Permissions révoquées spécifiquement
  final List<String> revokedPermissions;
  
  /// Préférences utilisateur
  final UserPreferences preferences;
  
  /// Métadonnées
  final DateTime createdAt;
  final DateTime lastLoginAt;
  final bool isActive;
  final bool isVerified;

  /// Constructeur du modèle utilisateur
  const User({
    required this.id,
    required this.email,
    required this.firstName,
    required this.lastName,
    required this.primaryRole,
    this.avatar,
    this.phone,
    this.organizationContexts = const [],
    this.additionalPermissions = const [],
    this.revokedPermissions = const [],
    this.preferences = const UserPreferences(),
    required this.createdAt,
    required this.lastLoginAt,
    this.isActive = true,
    this.isVerified = false,
  });



  /// Nom complet de l'utilisateur
  String get fullName => '$firstName $lastName';

  /// Initiales de l'utilisateur
  String get initials => '${firstName[0]}${lastName[0]}'.toUpperCase();

  /// Vérifie si l'utilisateur a une permission dans le contexte actuel
  bool hasPermission(String permission, {String? organizationId}) {
    // Vérification des permissions révoquées
    if (revokedPermissions.contains(permission)) return false;
    
    // Vérification des permissions additionnelles
    if (additionalPermissions.contains(permission)) return true;
    
    // Vérification du rôle principal
    if (primaryRole.hasPermission(permission)) return true;
    
    // Vérification dans le contexte organisationnel spécifique
    if (organizationId != null) {
      final context = getOrganizationContext(organizationId);
      if (context?.role.hasPermission(permission) == true) return true;
    }
    
    // Vérification dans tous les contextes organisationnels
    return organizationContexts.any((context) => 
      context.role.hasPermission(permission));
  }

  /// Obtient le contexte organisationnel pour une organisation
  UserOrganizationContext? getOrganizationContext(String organizationId) {
    try {
      return organizationContexts.firstWhere(
        (context) => context.organizationId == organizationId,
      );
    } catch (e) {
      return null;
    }
  }

  /// Obtient le rôle dans une organisation spécifique
  UserRole getRoleInOrganization(String organizationId) {
    final context = getOrganizationContext(organizationId);
    return context?.role ?? primaryRole;
  }

  /// Vérifie si l'utilisateur est membre d'une organisation
  bool isMemberOfOrganization(String organizationId) {
    return organizationContexts.any(
      (context) => context.organizationId == organizationId,
    );
  }

  /// Obtient toutes les permissions effectives de l'utilisateur
  List<String> getEffectivePermissions({String? organizationId}) {
    final permissions = <String>{};
    
    // Permissions du rôle principal
    permissions.addAll(primaryRole.getEffectivePermissions());
    
    // Permissions des contextes organisationnels
    if (organizationId != null) {
      final context = getOrganizationContext(organizationId);
      if (context != null) {
        permissions.addAll(context.role.getEffectivePermissions());
      }
    } else {
      for (final context in organizationContexts) {
        permissions.addAll(context.role.getEffectivePermissions());
      }
    }
    
    // Permissions additionnelles
    permissions.addAll(additionalPermissions);
    
    // Retirer les permissions révoquées
    permissions.removeAll(revokedPermissions);
    
    return permissions.toList()..sort();
  }

  /// Crée une copie de l'utilisateur avec des modifications
  User copyWith({
    String? email,
    String? firstName,
    String? lastName,
    String? avatar,
    String? phone,
    UserRole? primaryRole,
    List<UserOrganizationContext>? organizationContexts,
    List<String>? additionalPermissions,
    List<String>? revokedPermissions,
    UserPreferences? preferences,
    DateTime? lastLoginAt,
    bool? isActive,
    bool? isVerified,
  }) {
    return User(
      id: id,
      email: email ?? this.email,
      firstName: firstName ?? this.firstName,
      lastName: lastName ?? this.lastName,
      avatar: avatar ?? this.avatar,
      phone: phone ?? this.phone,
      primaryRole: primaryRole ?? this.primaryRole,
      organizationContexts: organizationContexts ?? this.organizationContexts,
      additionalPermissions: additionalPermissions ?? this.additionalPermissions,
      revokedPermissions: revokedPermissions ?? this.revokedPermissions,
      preferences: preferences ?? this.preferences,
      createdAt: createdAt,
      lastLoginAt: lastLoginAt ?? this.lastLoginAt,
      isActive: isActive ?? this.isActive,
      isVerified: isVerified ?? this.isVerified,
    );
  }

  /// Conversion vers Map pour sérialisation
  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'email': email,
      'firstName': firstName,
      'lastName': lastName,
      'avatar': avatar,
      'phone': phone,
      'primaryRole': primaryRole.name,
      'organizationContexts': organizationContexts.map((c) => c.toJson()).toList(),
      'additionalPermissions': additionalPermissions,
      'revokedPermissions': revokedPermissions,
      'preferences': preferences.toJson(),
      'createdAt': createdAt.toIso8601String(),
      'lastLoginAt': lastLoginAt.toIso8601String(),
      'isActive': isActive,
      'isVerified': isVerified,
    };
  }

  /// Création depuis Map pour désérialisation
  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'],
      email: json['email'],
      firstName: json['firstName'],
      lastName: json['lastName'],
      avatar: json['avatar'],
      phone: json['phone'],
      primaryRole: UserRole.fromString(json['primaryRole']) ?? UserRole.visitor,
      organizationContexts: (json['organizationContexts'] as List?)
          ?.map((c) => UserOrganizationContext.fromJson(c))
          .toList() ?? [],
      additionalPermissions: List<String>.from(json['additionalPermissions'] ?? []),
      revokedPermissions: List<String>.from(json['revokedPermissions'] ?? []),
      preferences: UserPreferences.fromJson(json['preferences'] ?? {}),
      createdAt: DateTime.parse(json['createdAt']),
      lastLoginAt: DateTime.parse(json['lastLoginAt']),
      isActive: json['isActive'] ?? true,
      isVerified: json['isVerified'] ?? false,
    );
  }

  @override
  List<Object?> get props => [
    id, email, firstName, lastName, avatar, phone, primaryRole,
    organizationContexts, additionalPermissions, revokedPermissions,
    preferences, createdAt, lastLoginAt, isActive, isVerified,
  ];
}

/// Contexte organisationnel d'un utilisateur
/// 
/// Définit le rôle et les permissions spécifiques dans une organisation
class UserOrganizationContext extends Equatable {
  /// Identifiant de l'organisation
  final String organizationId;
  
  /// Nom de l'organisation
  final String organizationName;
  
  /// Rôle de l'utilisateur dans cette organisation
  final UserRole role;
  
  /// Permissions spécifiques dans cette organisation
  final List<String> specificPermissions;
  
  /// Date d'adhésion à l'organisation
  final DateTime joinedAt;
  
  /// Statut dans l'organisation
  final bool isActive;

  /// Constructeur du contexte organisationnel
  const UserOrganizationContext({
    required this.organizationId,
    required this.organizationName,
    required this.role,
    this.specificPermissions = const [],
    required this.joinedAt,
    this.isActive = true,
  });

  /// Conversion vers Map
  Map<String, dynamic> toJson() {
    return {
      'organizationId': organizationId,
      'organizationName': organizationName,
      'role': role.name,
      'specificPermissions': specificPermissions,
      'joinedAt': joinedAt.toIso8601String(),
      'isActive': isActive,
    };
  }

  /// Création depuis Map
  factory UserOrganizationContext.fromJson(Map<String, dynamic> json) {
    return UserOrganizationContext(
      organizationId: json['organizationId'],
      organizationName: json['organizationName'],
      role: UserRole.fromString(json['role']) ?? UserRole.visitor,
      specificPermissions: List<String>.from(json['specificPermissions'] ?? []),
      joinedAt: DateTime.parse(json['joinedAt']),
      isActive: json['isActive'] ?? true,
    );
  }

  @override
  List<Object?> get props => [
    organizationId, organizationName, role, specificPermissions, joinedAt, isActive,
  ];
}

/// Préférences utilisateur personnalisables
class UserPreferences extends Equatable {
  /// Langue préférée
  final String language;
  
  /// Thème préféré
  final String theme;
  
  /// Notifications activées
  final bool notificationsEnabled;
  
  /// Notifications par email
  final bool emailNotifications;
  
  /// Notifications push
  final bool pushNotifications;
  
  /// Layout du dashboard préféré
  final String dashboardLayout;
  
  /// Timezone
  final String timezone;

  /// Constructeur des préférences
  const UserPreferences({
    this.language = 'fr',
    this.theme = 'system',
    this.notificationsEnabled = true,
    this.emailNotifications = true,
    this.pushNotifications = true,
    this.dashboardLayout = 'default',
    this.timezone = 'Europe/Paris',
  });

  /// Conversion vers Map
  Map<String, dynamic> toJson() {
    return {
      'language': language,
      'theme': theme,
      'notificationsEnabled': notificationsEnabled,
      'emailNotifications': emailNotifications,
      'pushNotifications': pushNotifications,
      'dashboardLayout': dashboardLayout,
      'timezone': timezone,
    };
  }

  /// Création depuis Map
  factory UserPreferences.fromJson(Map<String, dynamic> json) {
    return UserPreferences(
      language: json['language'] ?? 'fr',
      theme: json['theme'] ?? 'system',
      notificationsEnabled: json['notificationsEnabled'] ?? true,
      emailNotifications: json['emailNotifications'] ?? true,
      pushNotifications: json['pushNotifications'] ?? true,
      dashboardLayout: json['dashboardLayout'] ?? 'default',
      timezone: json['timezone'] ?? 'Europe/Paris',
    );
  }

  @override
  List<Object?> get props => [
    language, theme, notificationsEnabled, emailNotifications,
    pushNotifications, dashboardLayout, timezone,
  ];
}
