/// Modèle pour les critères de recherche avancée des membres
/// Correspond au DTO Java MembreSearchCriteria
class MembreSearchCriteria {
  /// Terme de recherche général (nom, prénom, email)
  final String? query;

  /// Recherche par nom exact ou partiel
  final String? nom;

  /// Recherche par prénom exact ou partiel
  final String? prenom;

  /// Recherche par email exact ou partiel
  final String? email;

  /// Filtre par numéro de téléphone
  final String? telephone;

  /// Liste des IDs d'organisations
  final List<String>? organisationIds;

  /// Liste des rôles à rechercher
  final List<String>? roles;

  /// Filtre par statut d'activité
  final String? statut;

  /// Date d'adhésion minimum (format ISO 8601)
  final String? dateAdhesionMin;

  /// Date d'adhésion maximum (format ISO 8601)
  final String? dateAdhesionMax;

  /// Âge minimum
  final int? ageMin;

  /// Âge maximum
  final int? ageMax;

  /// Filtre par région
  final String? region;

  /// Filtre par ville
  final String? ville;

  /// Filtre par profession
  final String? profession;

  /// Filtre par nationalité
  final String? nationalite;

  /// Filtre membres du bureau uniquement
  final bool? membreBureau;

  /// Filtre responsables uniquement
  final bool? responsable;

  /// Inclure les membres inactifs dans la recherche
  final bool includeInactifs;

  const MembreSearchCriteria({
    this.query,
    this.nom,
    this.prenom,
    this.email,
    this.telephone,
    this.organisationIds,
    this.roles,
    this.statut,
    this.dateAdhesionMin,
    this.dateAdhesionMax,
    this.ageMin,
    this.ageMax,
    this.region,
    this.ville,
    this.profession,
    this.nationalite,
    this.membreBureau,
    this.responsable,
    this.includeInactifs = false,
  });

  /// Factory constructor pour créer depuis JSON
  factory MembreSearchCriteria.fromJson(Map<String, dynamic> json) {
    return MembreSearchCriteria(
      query: json['query'] as String?,
      nom: json['nom'] as String?,
      prenom: json['prenom'] as String?,
      email: json['email'] as String?,
      telephone: json['telephone'] as String?,
      organisationIds: (json['organisationIds'] as List<dynamic>?)?.cast<String>(),
      roles: (json['roles'] as List<dynamic>?)?.cast<String>(),
      statut: json['statut'] as String?,
      dateAdhesionMin: json['dateAdhesionMin'] as String?,
      dateAdhesionMax: json['dateAdhesionMax'] as String?,
      ageMin: json['ageMin'] as int?,
      ageMax: json['ageMax'] as int?,
      region: json['region'] as String?,
      ville: json['ville'] as String?,
      profession: json['profession'] as String?,
      nationalite: json['nationalite'] as String?,
      membreBureau: json['membreBureau'] as bool?,
      responsable: json['responsable'] as bool?,
      includeInactifs: json['includeInactifs'] as bool? ?? false,
    );
  }

  /// Convertit vers JSON
  Map<String, dynamic> toJson() {
    return {
      'query': query,
      'nom': nom,
      'prenom': prenom,
      'email': email,
      'telephone': telephone,
      'organisationIds': organisationIds,
      'roles': roles,
      'statut': statut,
      'dateAdhesionMin': dateAdhesionMin,
      'dateAdhesionMax': dateAdhesionMax,
      'ageMin': ageMin,
      'ageMax': ageMax,
      'region': region,
      'ville': ville,
      'profession': profession,
      'nationalite': nationalite,
      'membreBureau': membreBureau,
      'responsable': responsable,
      'includeInactifs': includeInactifs,
    };
  }

  /// Vérifie si au moins un critère de recherche est défini
  bool get hasAnyCriteria {
    return query?.isNotEmpty == true ||
        nom?.isNotEmpty == true ||
        prenom?.isNotEmpty == true ||
        email?.isNotEmpty == true ||
        telephone?.isNotEmpty == true ||
        organisationIds?.isNotEmpty == true ||
        roles?.isNotEmpty == true ||
        statut?.isNotEmpty == true ||
        dateAdhesionMin?.isNotEmpty == true ||
        dateAdhesionMax?.isNotEmpty == true ||
        ageMin != null ||
        ageMax != null ||
        region?.isNotEmpty == true ||
        ville?.isNotEmpty == true ||
        profession?.isNotEmpty == true ||
        nationalite?.isNotEmpty == true ||
        membreBureau != null ||
        responsable != null;
  }

  /// Valide la cohérence des critères de recherche
  bool get isValid {
    // Validation des âges
    if (ageMin != null && ageMax != null) {
      if (ageMin! > ageMax!) {
        return false;
      }
    }

    // Validation des dates (si implémentée)
    if (dateAdhesionMin != null && dateAdhesionMax != null) {
      try {
        final dateMin = DateTime.parse(dateAdhesionMin!);
        final dateMax = DateTime.parse(dateAdhesionMax!);
        if (dateMin.isAfter(dateMax)) {
          return false;
        }
      } catch (e) {
        return false;
      }
    }

    return true;
  }

  /// Retourne une description textuelle des critères actifs
  String get description {
    final parts = <String>[];

    if (query?.isNotEmpty == true) parts.add("Recherche: '$query'");
    if (nom?.isNotEmpty == true) parts.add("Nom: '$nom'");
    if (prenom?.isNotEmpty == true) parts.add("Prénom: '$prenom'");
    if (email?.isNotEmpty == true) parts.add("Email: '$email'");
    if (statut?.isNotEmpty == true) parts.add("Statut: $statut");
    if (organisationIds?.isNotEmpty == true) {
      parts.add("Organisations: ${organisationIds!.length}");
    }
    if (roles?.isNotEmpty == true) {
      parts.add("Rôles: ${roles!.join(', ')}");
    }
    if (dateAdhesionMin?.isNotEmpty == true) {
      parts.add("Adhésion >= $dateAdhesionMin");
    }
    if (dateAdhesionMax?.isNotEmpty == true) {
      parts.add("Adhésion <= $dateAdhesionMax");
    }
    if (ageMin != null) parts.add("Âge >= $ageMin");
    if (ageMax != null) parts.add("Âge <= $ageMax");
    if (region?.isNotEmpty == true) parts.add("Région: '$region'");
    if (ville?.isNotEmpty == true) parts.add("Ville: '$ville'");
    if (profession?.isNotEmpty == true) parts.add("Profession: '$profession'");
    if (nationalite?.isNotEmpty == true) parts.add("Nationalité: '$nationalite'");
    if (membreBureau == true) parts.add("Membre bureau");
    if (responsable == true) parts.add("Responsable");

    return parts.join(' • ');
  }

  /// Crée une copie avec des modifications
  MembreSearchCriteria copyWith({
    String? query,
    String? nom,
    String? prenom,
    String? email,
    String? telephone,
    List<String>? organisationIds,
    List<String>? roles,
    String? statut,
    String? dateAdhesionMin,
    String? dateAdhesionMax,
    int? ageMin,
    int? ageMax,
    String? region,
    String? ville,
    String? profession,
    String? nationalite,
    bool? membreBureau,
    bool? responsable,
    bool? includeInactifs,
  }) {
    return MembreSearchCriteria(
      query: query ?? this.query,
      nom: nom ?? this.nom,
      prenom: prenom ?? this.prenom,
      email: email ?? this.email,
      telephone: telephone ?? this.telephone,
      organisationIds: organisationIds ?? this.organisationIds,
      roles: roles ?? this.roles,
      statut: statut ?? this.statut,
      dateAdhesionMin: dateAdhesionMin ?? this.dateAdhesionMin,
      dateAdhesionMax: dateAdhesionMax ?? this.dateAdhesionMax,
      ageMin: ageMin ?? this.ageMin,
      ageMax: ageMax ?? this.ageMax,
      region: region ?? this.region,
      ville: ville ?? this.ville,
      profession: profession ?? this.profession,
      nationalite: nationalite ?? this.nationalite,
      membreBureau: membreBureau ?? this.membreBureau,
      responsable: responsable ?? this.responsable,
      includeInactifs: includeInactifs ?? this.includeInactifs,
    );
  }

  /// Critères vides
  static const empty = MembreSearchCriteria();

  /// Critères pour recherche rapide par nom/prénom
  static MembreSearchCriteria quickSearch(String query) {
    return MembreSearchCriteria(query: query);
  }

  /// Critères pour membres actifs uniquement
  static const activeMembers = MembreSearchCriteria(
    statut: 'ACTIF',
    includeInactifs: false,
  );

  /// Critères pour membres du bureau
  static const bureauMembers = MembreSearchCriteria(
    membreBureau: true,
    statut: 'ACTIF',
  );

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is MembreSearchCriteria &&
          runtimeType == other.runtimeType &&
          query == other.query &&
          nom == other.nom &&
          prenom == other.prenom &&
          email == other.email &&
          telephone == other.telephone &&
          organisationIds == other.organisationIds &&
          roles == other.roles &&
          statut == other.statut &&
          dateAdhesionMin == other.dateAdhesionMin &&
          dateAdhesionMax == other.dateAdhesionMax &&
          ageMin == other.ageMin &&
          ageMax == other.ageMax &&
          region == other.region &&
          ville == other.ville &&
          profession == other.profession &&
          nationalite == other.nationalite &&
          membreBureau == other.membreBureau &&
          responsable == other.responsable &&
          includeInactifs == other.includeInactifs;

  @override
  int get hashCode => Object.hashAll([
        query,
        nom,
        prenom,
        email,
        telephone,
        organisationIds,
        roles,
        statut,
        dateAdhesionMin,
        dateAdhesionMax,
        ageMin,
        ageMax,
        region,
        ville,
        profession,
        nationalite,
        membreBureau,
        responsable,
        includeInactifs,
      ]);

  @override
  String toString() => 'MembreSearchCriteria(${description.isNotEmpty ? description : 'empty'})';
}
