/// Repository pour la gestion des membres
/// Interface avec l'API backend MembreResource
library membre_repository;

import 'package:dio/dio.dart';
import '../models/membre_complete_model.dart';
import '../../../../shared/models/membre_search_result.dart';
import '../../../../shared/models/membre_search_criteria.dart';

/// Interface du repository des membres
abstract class MembreRepository {
  /// Récupère la liste des membres avec pagination
  Future<MembreSearchResult> getMembres({
    int page = 0,
    int size = 20,
    String? recherche,
  });

  /// Récupère un membre par son ID
  Future<MembreCompletModel?> getMembreById(String id);

  /// Crée un nouveau membre
  Future<MembreCompletModel> createMembre(MembreCompletModel membre);

  /// Met à jour un membre
  Future<MembreCompletModel> updateMembre(String id, MembreCompletModel membre);

  /// Supprime un membre
  Future<void> deleteMembre(String id);

  /// Active un membre
  Future<MembreCompletModel> activateMembre(String id);

  /// Désactive un membre
  Future<MembreCompletModel> deactivateMembre(String id);

  /// Recherche avancée de membres
  Future<MembreSearchResult> searchMembres({
    required MembreSearchCriteria criteria,
    int page = 0,
    int size = 20,
  });

  /// Récupère les membres actifs
  Future<MembreSearchResult> getActiveMembers({int page = 0, int size = 20});

  /// Récupère les membres du bureau
  Future<MembreSearchResult> getBureauMembers({int page = 0, int size = 20});

  /// Récupère les statistiques des membres
  Future<Map<String, dynamic>> getMembresStats();
}

/// Implémentation du repository des membres
class MembreRepositoryImpl implements MembreRepository {
  final Dio _dio;
  static const String _baseUrl = '/api/membres';

  MembreRepositoryImpl(this._dio);

  @override
  Future<MembreSearchResult> getMembres({
    int page = 0,
    int size = 20,
    String? recherche,
  }) async {
    try {
      // Si une recherche est fournie, utiliser l'endpoint de recherche
      if (recherche?.isNotEmpty == true) {
        final response = await _dio.get(
          '$_baseUrl/recherche',
          queryParameters: {
            'q': recherche,
            'page': page,
            'size': size,
          },
        );

        return _parseMembreSearchResult(response, page, size, MembreSearchCriteria(query: recherche));
      }

      // Sinon, récupérer tous les membres
      final response = await _dio.get(
        _baseUrl,
        queryParameters: {
          'page': page,
          'size': size,
        },
      );

      return _parseMembreSearchResult(response, page, size, const MembreSearchCriteria());
    } on DioException catch (e) {
      throw Exception('Erreur réseau lors de la récupération des membres: ${e.message}');
    } catch (e) {
      throw Exception('Erreur inattendue lors de la récupération des membres: $e');
    }
  }

  /// Parse la réponse API et retourne un MembreSearchResult
  /// Gère les deux formats possibles : List (simple) ou Map (paginé)
  MembreSearchResult _parseMembreSearchResult(
    Response response,
    int page,
    int size,
    MembreSearchCriteria criteria,
  ) {
    if (response.statusCode != 200) {
      throw Exception('Erreur HTTP: ${response.statusCode}');
    }

    // Format simple : liste directe de membres
    if (response.data is List) {
      final List<dynamic> listData = response.data as List<dynamic>;
      final membres = listData
          .map((e) => MembreCompletModel.fromJson(e as Map<String, dynamic>))
          .toList();

      return MembreSearchResult(
        membres: membres,
        totalElements: membres.length,
        totalPages: 1,
        currentPage: page,
        pageSize: membres.length,
        numberOfElements: membres.length,
        hasNext: false,
        hasPrevious: false,
        isFirst: true,
        isLast: true,
        criteria: criteria,
        executionTimeMs: 0,
      );
    }

    // Format paginé : objet avec métadonnées
    return MembreSearchResult.fromJson(response.data as Map<String, dynamic>);
  }



  @override
  Future<MembreCompletModel?> getMembreById(String id) async {
    try {
      final response = await _dio.get('$_baseUrl/$id');

      if (response.statusCode == 200) {
        return MembreCompletModel.fromJson(response.data as Map<String, dynamic>);
      } else if (response.statusCode == 404) {
        return null;
      } else {
        throw Exception('Erreur lors de la récupération du membre: ${response.statusCode}');
      }
    } on DioException catch (e) {
      if (e.response?.statusCode == 404) {
        return null;
      }
      throw Exception('Erreur réseau lors de la récupération du membre: ${e.message}');
    } catch (e) {
      throw Exception('Erreur inattendue lors de la récupération du membre: $e');
    }
  }

  @override
  Future<MembreCompletModel> createMembre(MembreCompletModel membre) async {
    try {
      final response = await _dio.post(
        _baseUrl,
        data: membre.toJson(),
      );

      if (response.statusCode == 201 || response.statusCode == 200) {
        return MembreCompletModel.fromJson(response.data as Map<String, dynamic>);
      } else {
        throw Exception('Erreur lors de la création du membre: ${response.statusCode}');
      }
    } on DioException catch (e) {
      throw Exception('Erreur réseau lors de la création du membre: ${e.message}');
    } catch (e) {
      throw Exception('Erreur inattendue lors de la création du membre: $e');
    }
  }

  @override
  Future<MembreCompletModel> updateMembre(String id, MembreCompletModel membre) async {
    try {
      final response = await _dio.put(
        '$_baseUrl/$id',
        data: membre.toJson(),
      );

      if (response.statusCode == 200) {
        return MembreCompletModel.fromJson(response.data as Map<String, dynamic>);
      } else {
        throw Exception('Erreur lors de la mise à jour du membre: ${response.statusCode}');
      }
    } on DioException catch (e) {
      throw Exception('Erreur réseau lors de la mise à jour du membre: ${e.message}');
    } catch (e) {
      throw Exception('Erreur inattendue lors de la mise à jour du membre: $e');
    }
  }

  @override
  Future<void> deleteMembre(String id) async {
    try {
      final response = await _dio.delete('$_baseUrl/$id');

      if (response.statusCode != 204 && response.statusCode != 200) {
        throw Exception('Erreur lors de la suppression du membre: ${response.statusCode}');
      }
    } on DioException catch (e) {
      throw Exception('Erreur réseau lors de la suppression du membre: ${e.message}');
    } catch (e) {
      throw Exception('Erreur inattendue lors de la suppression du membre: $e');
    }
  }

  @override
  Future<MembreCompletModel> activateMembre(String id) async {
    try {
      final response = await _dio.post('$_baseUrl/$id/activer');

      if (response.statusCode == 200) {
        return MembreCompletModel.fromJson(response.data as Map<String, dynamic>);
      } else {
        throw Exception('Erreur lors de l\'activation du membre: ${response.statusCode}');
      }
    } on DioException catch (e) {
      throw Exception('Erreur réseau lors de l\'activation du membre: ${e.message}');
    } catch (e) {
      throw Exception('Erreur inattendue lors de l\'activation du membre: $e');
    }
  }

  @override
  Future<MembreCompletModel> deactivateMembre(String id) async {
    try {
      final response = await _dio.post('$_baseUrl/$id/desactiver');

      if (response.statusCode == 200) {
        return MembreCompletModel.fromJson(response.data as Map<String, dynamic>);
      } else {
        throw Exception('Erreur lors de la désactivation du membre: ${response.statusCode}');
      }
    } on DioException catch (e) {
      throw Exception('Erreur réseau lors de la désactivation du membre: ${e.message}');
    } catch (e) {
      throw Exception('Erreur inattendue lors de la désactivation du membre: $e');
    }
  }

  @override
  Future<MembreSearchResult> searchMembres({
    required MembreSearchCriteria criteria,
    int page = 0,
    int size = 20,
  }) async {
    try {
      // Les paramètres de pagination vont dans queryParameters
      // Les critères de recherche vont directement dans le body
      final response = await _dio.post(
        '$_baseUrl/search/advanced',
        queryParameters: {
          'page': page,
          'size': size,
        },
        data: criteria.toJson(),
      );

      return _parseMembreSearchResult(response, page, size, criteria);
    } on DioException catch (e) {
      throw Exception('Erreur réseau lors de la recherche de membres: ${e.message}');
    } catch (e) {
      throw Exception('Erreur inattendue lors de la recherche de membres: $e');
    }
  }

  @override
  Future<MembreSearchResult> getActiveMembers({int page = 0, int size = 20}) async {
    // Utiliser la recherche avancée avec le critère statut=ACTIF
    return searchMembres(
      criteria: const MembreSearchCriteria(
        statut: 'ACTIF',
        includeInactifs: false,
      ),
      page: page,
      size: size,
    );
  }

  @override
  Future<MembreSearchResult> getBureauMembers({int page = 0, int size = 20}) async {
    // Utiliser la recherche avancée avec le critère membreBureau=true
    return searchMembres(
      criteria: const MembreSearchCriteria(
        membreBureau: true,
        statut: 'ACTIF',
      ),
      page: page,
      size: size,
    );
  }

  @override
  Future<Map<String, dynamic>> getMembresStats() async {
    try {
      final response = await _dio.get('$_baseUrl/statistiques');

      if (response.statusCode == 200) {
        return response.data as Map<String, dynamic>;
      } else {
        throw Exception('Erreur lors de la récupération des statistiques: ${response.statusCode}');
      }
    } on DioException catch (e) {
      throw Exception('Erreur réseau lors de la récupération des statistiques: ${e.message}');
    } catch (e) {
      throw Exception('Erreur inattendue lors de la récupération des statistiques: $e');
    }
  }
}

