import 'membre_search_criteria.dart';
import '../../features/members/data/models/membre_complete_model.dart';

/// Modèle pour les résultats de recherche avancée des membres
/// Correspond au DTO Java MembreSearchResultDTO
class MembreSearchResult {
  /// Liste des membres trouvés
  final List<MembreCompletModel> membres;

  /// Nombre total de résultats (toutes pages confondues)
  final int totalElements;

  /// Nombre total de pages
  final int totalPages;

  /// Numéro de la page actuelle (0-based)
  final int currentPage;

  /// Taille de la page
  final int pageSize;

  /// Nombre d'éléments sur la page actuelle
  final int numberOfElements;

  /// Indique s'il y a une page suivante
  final bool hasNext;

  /// Indique s'il y a une page précédente
  final bool hasPrevious;

  /// Indique si c'est la première page
  final bool isFirst;

  /// Indique si c'est la dernière page
  final bool isLast;

  /// Critères de recherche utilisés
  final MembreSearchCriteria criteria;

  /// Temps d'exécution de la recherche en millisecondes
  final int executionTimeMs;

  /// Statistiques de recherche
  final SearchStatistics? statistics;

  const MembreSearchResult({
    required this.membres,
    required this.totalElements,
    required this.totalPages,
    required this.currentPage,
    required this.pageSize,
    required this.numberOfElements,
    required this.hasNext,
    required this.hasPrevious,
    required this.isFirst,
    required this.isLast,
    required this.criteria,
    required this.executionTimeMs,
    this.statistics,
  });

  /// Factory constructor pour créer depuis JSON
  factory MembreSearchResult.fromJson(Map<String, dynamic> json) {
    return MembreSearchResult(
      membres: (json['membres'] as List<dynamic>?)
          ?.map((e) => MembreCompletModel.fromJson(e as Map<String, dynamic>))
          .toList() ?? [],
      totalElements: json['totalElements'] as int? ?? 0,
      totalPages: json['totalPages'] as int? ?? 0,
      currentPage: json['currentPage'] as int? ?? 0,
      pageSize: json['pageSize'] as int? ?? 20,
      numberOfElements: json['numberOfElements'] as int? ?? 0,
      hasNext: json['hasNext'] as bool? ?? false,
      hasPrevious: json['hasPrevious'] as bool? ?? false,
      isFirst: json['isFirst'] as bool? ?? true,
      isLast: json['isLast'] as bool? ?? true,
      criteria: MembreSearchCriteria.fromJson(json['criteria'] as Map<String, dynamic>? ?? {}),
      executionTimeMs: json['executionTimeMs'] as int? ?? 0,
      statistics: json['statistics'] != null
          ? SearchStatistics.fromJson(json['statistics'] as Map<String, dynamic>)
          : null,
    );
  }

  /// Convertit vers JSON
  Map<String, dynamic> toJson() {
    return {
      'membres': membres.map((e) => e.toJson()).toList(),
      'totalElements': totalElements,
      'totalPages': totalPages,
      'currentPage': currentPage,
      'pageSize': pageSize,
      'numberOfElements': numberOfElements,
      'hasNext': hasNext,
      'hasPrevious': hasPrevious,
      'isFirst': isFirst,
      'isLast': isLast,
      'criteria': criteria.toJson(),
      'executionTimeMs': executionTimeMs,
      'statistics': statistics?.toJson(),
    };
  }

  /// Vérifie si les résultats sont vides
  bool get isEmpty => membres.isEmpty;

  /// Vérifie si les résultats ne sont pas vides
  bool get isNotEmpty => membres.isNotEmpty;

  /// Retourne le numéro de la page suivante (1-based pour affichage)
  int get nextPageNumber => hasNext ? currentPage + 2 : -1;

  /// Retourne le numéro de la page précédente (1-based pour affichage)
  int get previousPageNumber => hasPrevious ? currentPage : -1;

  /// Retourne une description textuelle des résultats
  String get resultDescription {
    if (isEmpty) {
      return 'Aucun membre trouvé';
    }

    if (totalElements == 1) {
      return '1 membre trouvé';
    }

    if (totalPages == 1) {
      return '$totalElements membres trouvés';
    }

    final startElement = currentPage * pageSize + 1;
    final endElement = (startElement + numberOfElements - 1).clamp(1, totalElements);

    return 'Membres $startElement-$endElement sur $totalElements (page ${currentPage + 1}/$totalPages)';
  }

  /// Résultat vide
  static MembreSearchResult empty(MembreSearchCriteria criteria) {
    return MembreSearchResult(
      membres: const [],
      totalElements: 0,
      totalPages: 0,
      currentPage: 0,
      pageSize: 20,
      numberOfElements: 0,
      hasNext: false,
      hasPrevious: false,
      isFirst: true,
      isLast: true,
      criteria: criteria,
      executionTimeMs: 0,
    );
  }

  @override
  String toString() => 'MembreSearchResult($resultDescription, ${executionTimeMs}ms)';
}

/// Statistiques sur les résultats de recherche
class SearchStatistics {
  /// Nombre de membres actifs dans les résultats
  final int membresActifs;

  /// Nombre de membres inactifs dans les résultats
  final int membresInactifs;

  /// Âge moyen des membres trouvés
  final double ageMoyen;

  /// Âge minimum des membres trouvés
  final int ageMin;

  /// Âge maximum des membres trouvés
  final int ageMax;

  /// Nombre d'organisations représentées
  final int nombreOrganisations;

  /// Nombre de régions représentées
  final int nombreRegions;

  /// Ancienneté moyenne en années
  final double ancienneteMoyenne;

  const SearchStatistics({
    required this.membresActifs,
    required this.membresInactifs,
    required this.ageMoyen,
    required this.ageMin,
    required this.ageMax,
    required this.nombreOrganisations,
    required this.nombreRegions,
    required this.ancienneteMoyenne,
  });

  /// Factory constructor pour créer depuis JSON
  factory SearchStatistics.fromJson(Map<String, dynamic> json) {
    return SearchStatistics(
      membresActifs: json['membresActifs'] as int? ?? 0,
      membresInactifs: json['membresInactifs'] as int? ?? 0,
      ageMoyen: (json['ageMoyen'] as num?)?.toDouble() ?? 0.0,
      ageMin: json['ageMin'] as int? ?? 0,
      ageMax: json['ageMax'] as int? ?? 0,
      nombreOrganisations: json['nombreOrganisations'] as int? ?? 0,
      nombreRegions: json['nombreRegions'] as int? ?? 0,
      ancienneteMoyenne: (json['ancienneteMoyenne'] as num?)?.toDouble() ?? 0.0,
    );
  }

  /// Convertit vers JSON
  Map<String, dynamic> toJson() {
    return {
      'membresActifs': membresActifs,
      'membresInactifs': membresInactifs,
      'ageMoyen': ageMoyen,
      'ageMin': ageMin,
      'ageMax': ageMax,
      'nombreOrganisations': nombreOrganisations,
      'nombreRegions': nombreRegions,
      'ancienneteMoyenne': ancienneteMoyenne,
    };
  }

  /// Nombre total de membres
  int get totalMembres => membresActifs + membresInactifs;

  /// Pourcentage de membres actifs
  double get pourcentageActifs {
    if (totalMembres == 0) return 0.0;
    return (membresActifs / totalMembres) * 100;
  }

  /// Pourcentage de membres inactifs
  double get pourcentageInactifs {
    if (totalMembres == 0) return 0.0;
    return (membresInactifs / totalMembres) * 100;
  }

  /// Tranche d'âge
  String get trancheAge {
    if (ageMin == ageMax) return '$ageMin ans';
    return '$ageMin-$ageMax ans';
  }

  /// Description textuelle des statistiques
  String get description {
    final parts = <String>[];

    if (totalMembres > 0) {
      parts.add('$totalMembres membres');
      if (membresActifs > 0) {
        parts.add('${pourcentageActifs.toStringAsFixed(1)}% actifs');
      }
      if (ageMoyen > 0) {
        parts.add('âge moyen: ${ageMoyen.toStringAsFixed(1)} ans');
      }
      if (nombreOrganisations > 0) {
        parts.add('$nombreOrganisations organisations');
      }
      if (ancienneteMoyenne > 0) {
        parts.add('ancienneté: ${ancienneteMoyenne.toStringAsFixed(1)} ans');
      }
    }

    return parts.join(' • ');
  }

  @override
  String toString() => 'SearchStatistics($description)';
}
