/// Service pour la gestion des organisations
/// Helpers pour tri, filtrage local et recherche
library organization_service;

import 'package:injectable/injectable.dart';
import '../models/organization_model.dart';
import '../../domain/repositories/organization_repository.dart';

/// Service de gestion des organisations (helpers uniquement)
@injectable
class OrganizationService {
  final IOrganizationRepository _repository;

  OrganizationService(this._repository);

  /// Récupère la liste des organisations avec pagination et recherche
  Future<List<OrganizationModel>> getOrganizations({
    int page = 0,
    int size = 20,
    String? recherche,
  }) async {
    try {
      return await _repository.getOrganizations(
        page: page,
        size: size,
        recherche: recherche,
      );
    } catch (e) {
      throw Exception('Erreur lors de la récupération des organisations: $e');
    }
  }

  /// Récupère les organisations du membre connecté (pour admin d'organisation)
  Future<List<OrganizationModel>> getMesOrganisations() async {
    try {
      return await _repository.getMesOrganisations();
    } catch (e) {
      throw Exception('Erreur lors de la récupération de mes organisations: $e');
    }
  }

  /// Récupère une organisation par son ID
  Future<OrganizationModel?> getOrganizationById(String id) async {
    if (id.isEmpty) {
      throw ArgumentError('L\'ID de l\'organisation ne peut pas être vide');
    }

    try {
      return await _repository.getOrganizationById(id);
    } catch (e) {
      throw Exception('Erreur lors de la récupération de l\'organisation: $e');
    }
  }

  /// Crée une nouvelle organisation avec validation
  Future<OrganizationModel> createOrganization(OrganizationModel organization) async {
    // Validation des données obligatoires
    _validateOrganization(organization);

    try {
      return await _repository.createOrganization(organization);
    } catch (e) {
      throw Exception('Erreur lors de la création de l\'organisation: $e');
    }
  }

  /// Met à jour une organisation avec validation
  Future<OrganizationModel> updateOrganization(String id, OrganizationModel organization) async {
    if (id.isEmpty) {
      throw ArgumentError('L\'ID de l\'organisation ne peut pas être vide');
    }

    // Validation des données obligatoires
    _validateOrganization(organization);

    try {
      return await _repository.updateOrganization(id, organization);
    } catch (e) {
      throw Exception('Erreur lors de la mise à jour de l\'organisation: $e');
    }
  }

  /// Supprime une organisation
  Future<void> deleteOrganization(String id) async {
    if (id.isEmpty) {
      throw ArgumentError('L\'ID de l\'organisation ne peut pas être vide');
    }

    try {
      await _repository.deleteOrganization(id);
    } catch (e) {
      throw Exception('Erreur lors de la suppression de l\'organisation: $e');
    }
  }

  /// Active une organisation
  Future<OrganizationModel> activateOrganization(String id) async {
    if (id.isEmpty) {
      throw ArgumentError('L\'ID de l\'organisation ne peut pas être vide');
    }

    try {
      return await _repository.activateOrganization(id);
    } catch (e) {
      throw Exception('Erreur lors de l\'activation de l\'organisation: $e');
    }
  }

  /// Suspend une organisation
  Future<OrganizationModel> suspendOrganization(String id) async {
    if (id.isEmpty) {
      throw ArgumentError('L\'ID de l\'organisation ne peut pas être vide');
    }

    try {
      return await _repository.suspendOrganization(id);
    } catch (e) {
      throw Exception('Erreur lors de la suspension de l\'organisation: $e');
    }
  }

  /// Recherche avancée d'organisations
  Future<List<OrganizationModel>> searchOrganizations({
    String? nom,
    String? type,
    StatutOrganization? statut,
    String? ville,
    String? region,
    String? pays,
    int page = 0,
    int size = 20,
  }) async {
    try {
      return await _repository.searchOrganizations(
        nom: nom,
        type: type,
        statut: statut,
        ville: ville,
        region: region,
        pays: pays,
        page: page,
        size: size,
      );
    } catch (e) {
      throw Exception('Erreur lors de la recherche d\'organisations: $e');
    }
  }

  /// Récupère les statistiques des organisations
  Future<Map<String, dynamic>> getOrganizationsStats() async {
    try {
      return await _repository.getOrganizationsStats();
    } catch (e) {
      throw Exception('Erreur lors de la récupération des statistiques: $e');
    }
  }

  /// Filtre les organisations par statut
  List<OrganizationModel> filterByStatus(
    List<OrganizationModel> organizations,
    StatutOrganization statut,
  ) {
    return organizations.where((org) => org.statut == statut).toList();
  }

  /// Filtre les organisations par type
  List<OrganizationModel> filterByType(
    List<OrganizationModel> organizations,
    String type,
  ) {
    return organizations.where((org) => org.typeOrganisation == type).toList();
  }

  /// Trie les organisations par nom
  List<OrganizationModel> sortByName(
    List<OrganizationModel> organizations, {
    bool ascending = true,
  }) {
    final sorted = List<OrganizationModel>.from(organizations);
    sorted.sort((a, b) {
      final comparison = a.nom.toLowerCase().compareTo(b.nom.toLowerCase());
      return ascending ? comparison : -comparison;
    });
    return sorted;
  }

  /// Trie les organisations par date de création
  List<OrganizationModel> sortByCreationDate(
    List<OrganizationModel> organizations, {
    bool ascending = true,
  }) {
    final sorted = List<OrganizationModel>.from(organizations);
    sorted.sort((a, b) {
      final dateA = a.dateCreation ?? DateTime.fromMillisecondsSinceEpoch(0);
      final dateB = b.dateCreation ?? DateTime.fromMillisecondsSinceEpoch(0);
      final comparison = dateA.compareTo(dateB);
      return ascending ? comparison : -comparison;
    });
    return sorted;
  }

  /// Trie les organisations par nombre de membres
  List<OrganizationModel> sortByMemberCount(
    List<OrganizationModel> organizations, {
    bool ascending = true,
  }) {
    final sorted = List<OrganizationModel>.from(organizations);
    sorted.sort((a, b) {
      final comparison = a.nombreMembres.compareTo(b.nombreMembres);
      return ascending ? comparison : -comparison;
    });
    return sorted;
  }

  /// Recherche locale dans une liste d'organisations
  List<OrganizationModel> searchLocal(
    List<OrganizationModel> organizations,
    String query,
  ) {
    if (query.isEmpty) return organizations;

    final lowerQuery = query.toLowerCase();
    return organizations.where((org) {
      return org.nom.toLowerCase().contains(lowerQuery) ||
          (org.nomCourt?.toLowerCase().contains(lowerQuery) ?? false) ||
          (org.description?.toLowerCase().contains(lowerQuery) ?? false) ||
          (org.ville?.toLowerCase().contains(lowerQuery) ?? false) ||
          (org.region?.toLowerCase().contains(lowerQuery) ?? false);
    }).toList();
  }

  /// Calcule les statistiques locales d'une liste d'organisations
  Map<String, dynamic> calculateLocalStats(List<OrganizationModel> organizations) {
    if (organizations.isEmpty) {
      return {
        'total': 0,
        'actives': 0,
        'inactives': 0,
        'totalMembres': 0,
        'moyenneMembres': 0.0,
        'parType': <String, int>{},
        'parStatut': <String, int>{},
      };
    }

    final actives = organizations.where((org) => org.statut == StatutOrganization.active).length;
    final inactives = organizations.length - actives;
    final totalMembres = organizations.fold<int>(0, (sum, org) => sum + org.nombreMembres);
    final moyenneMembres = totalMembres / organizations.length;

    // Statistiques par type
    final parType = <String, int>{};
    for (final org in organizations) {
      final type = org.typeOrganisation;
      parType[type] = (parType[type] ?? 0) + 1;
    }

    // Statistiques par statut
    final parStatut = <String, int>{};
    for (final org in organizations) {
      final statut = org.statut.displayName;
      parStatut[statut] = (parStatut[statut] ?? 0) + 1;
    }

    return {
      'total': organizations.length,
      'actives': actives,
      'inactives': inactives,
      'totalMembres': totalMembres,
      'moyenneMembres': moyenneMembres,
      'parType': parType,
      'parStatut': parStatut,
    };
  }

  /// Validation des données d'organisation
  void _validateOrganization(OrganizationModel organization) {
    if (organization.nom.trim().isEmpty) {
      throw ArgumentError('Le nom de l\'organisation est obligatoire');
    }

    if (organization.nom.trim().length < 2) {
      throw ArgumentError('Le nom de l\'organisation doit contenir au moins 2 caractères');
    }

    if (organization.nom.trim().length > 200) {
      throw ArgumentError('Le nom de l\'organisation ne peut pas dépasser 200 caractères');
    }

    if (organization.nomCourt != null && organization.nomCourt!.length > 50) {
      throw ArgumentError('Le nom court ne peut pas dépasser 50 caractères');
    }

    if (organization.email != null && organization.email!.isNotEmpty) {
      if (!_isValidEmail(organization.email!)) {
        throw ArgumentError('L\'adresse email n\'est pas valide');
      }
    }

    if (organization.telephone != null && organization.telephone!.isNotEmpty) {
      if (!_isValidPhone(organization.telephone!)) {
        throw ArgumentError('Le numéro de téléphone n\'est pas valide');
      }
    }

    if (organization.siteWeb != null && organization.siteWeb!.isNotEmpty) {
      if (!_isValidUrl(organization.siteWeb!)) {
        throw ArgumentError('L\'URL du site web n\'est pas valide');
      }
    }

    if (organization.budgetAnnuel != null && organization.budgetAnnuel! < 0) {
      throw ArgumentError('Le budget annuel doit être positif');
    }

    if (organization.montantCotisationAnnuelle != null && organization.montantCotisationAnnuelle! < 0) {
      throw ArgumentError('Le montant de cotisation doit être positif');
    }
  }

  /// Validation d'email
  bool _isValidEmail(String email) {
    return RegExp(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$').hasMatch(email);
  }

  /// Validation de téléphone
  bool _isValidPhone(String phone) {
    return RegExp(r'^\+?[0-9\s\-\(\)]{8,15}$').hasMatch(phone);
  }

  /// Validation d'URL
  bool _isValidUrl(String url) {
    try {
      final uri = Uri.parse(url);
      return uri.hasScheme && (uri.scheme == 'http' || uri.scheme == 'https');
    } catch (e) {
      return false;
    }
  }
}
