/// Repository pour la gestion des rapports et analytics
library reports_repository_impl;

import 'package:dio/dio.dart';
import 'package:injectable/injectable.dart';
import 'package:unionflow_mobile_apps/core/network/api_client.dart';
import 'package:unionflow_mobile_apps/core/utils/logger.dart';
import '../../domain/repositories/reports_repository.dart';
import '../models/analytics_model.dart';

/// Implémentation du repository des rapports
@LazySingleton(as: IReportsRepository)
class ReportsRepositoryImpl implements IReportsRepository {
  final ApiClient _apiClient;
  static const String _analyticsBase = '/api/v1/analytics';
  static const String _membresBase = '/api/membres';
  static const String _cotisationsBase = '/api/cotisations';
  static const String _evenementsBase = '/api/evenements';

  ReportsRepositoryImpl(this._apiClient);

  @override
  Future<List<AnalyticsModel>> getMetriques(String typeMetrique, String periode) async {
    try {
      final response = await _apiClient.get(
        '$_analyticsBase/metriques/$typeMetrique',
        queryParameters: {'periodeAnalyse': periode},
      );
      if (response.statusCode == 200) {
        final data = response.data;
        if (data is List) {
          return data.map((e) => AnalyticsModel.fromJson(e as Map<String, dynamic>)).toList();
        }
        if (data is Map) {
          return [AnalyticsModel.fromJson(data as Map<String, dynamic>)];
        }
      }
      return [];
    } on DioException catch (e, st) {
      AppLogger.error('ReportsRepository: getMetriques échoué', error: e, stackTrace: st);
      if (e.response?.statusCode == 404 || e.response?.statusCode == 400) return [];
      rethrow;
    }
  }

  @override
  Future<Map<String, dynamic>> getPerformanceGlobale() async {
    try {
      final response = await _apiClient.get('$_analyticsBase/performance-globale');
      if (response.statusCode == 200 && response.data is Map) {
        return response.data as Map<String, dynamic>;
      }
      return {};
    } on DioException catch (e, st) {
      AppLogger.error('ReportsRepository: getPerformanceGlobale échoué', error: e, stackTrace: st);
      return {};
    }
  }

  @override
  Future<List<AnalyticsModel>> getEvolutions(String typeMetrique) async {
    try {
      final response = await _apiClient.get(
        '$_analyticsBase/evolutions',
        queryParameters: {'typeMetrique': typeMetrique},
      );
      if (response.statusCode == 200) {
        final data = response.data;
        if (data is List) {
          return data.map((e) => AnalyticsModel.fromJson(e as Map<String, dynamic>)).toList();
        }
      }
      return [];
    } on DioException catch (e, st) {
      AppLogger.error('ReportsRepository: getEvolutions échoué', error: e, stackTrace: st);
      return [];
    }
  }

  @override
  Future<Map<String, dynamic>> getStatistiquesMembres() async {
    try {
      final response = await _apiClient.get('$_membresBase/statistiques');
      if (response.statusCode == 200 && response.data is Map) {
        return response.data as Map<String, dynamic>;
      }
      return {};
    } on DioException catch (e, st) {
      AppLogger.error('ReportsRepository: getStatistiquesMembres échoué', error: e, stackTrace: st);
      return {};
    }
  }

  @override
  Future<Map<String, dynamic>> getStatistiquesCotisations(int annee) async {
    try {
      final response = await _apiClient.get(
        '$_cotisationsBase/statistiques',
        queryParameters: {'annee': annee},
      );
      if (response.statusCode == 200 && response.data is Map) {
        return response.data as Map<String, dynamic>;
      }
      return {};
    } on DioException catch (e, st) {
      AppLogger.error('ReportsRepository: getStatistiquesCotisations échoué', error: e, stackTrace: st);
      return {};
    }
  }

  @override
  Future<Map<String, dynamic>> getStatistiquesEvenements() async {
    try {
      final response = await _apiClient.get('$_evenementsBase/statistiques');
      if (response.statusCode == 200 && response.data is Map) {
        return response.data as Map<String, dynamic>;
      }
      return {};
    } on DioException catch (e, st) {
      AppLogger.error('ReportsRepository: getStatistiquesEvenements échoué', error: e, stackTrace: st);
      return {};
    }
  }

  @override
  Future<List<Map<String, dynamic>>> getAvailableReports() async {
    try {
      final response = await _apiClient.get('$_analyticsBase/reports/available');
      if (response.statusCode == 200) {
        final data = response.data;
        if (data is List) {
          return data.map((e) => Map<String, dynamic>.from(e as Map)).toList();
        }
      }
      return [];
    } on DioException catch (e, st) {
      AppLogger.error('ReportsRepository: getAvailableReports échoué', error: e, stackTrace: st);
      return [];
    }
  }

  @override
  Future<void> generateReport(String type, {String? format}) async {
    try {
      final queryParams = <String, dynamic>{'type': type};
      if (format != null) queryParams['format'] = format;
      final response = await _apiClient.post(
        '$_analyticsBase/reports/generate',
        queryParameters: queryParams,
      );
      if (response.statusCode != 200 && response.statusCode != 201 && response.statusCode != 202) {
        throw Exception('Generate report failed: ${response.statusCode}');
      }
    } on DioException catch (e, st) {
      AppLogger.error('ReportsRepository: generateReport échoué', error: e, stackTrace: st);
      rethrow;
    }
  }

  @override
  Future<String> exportReportPdf(String type) async {
    try {
      final response = await _apiClient.post(
        '$_analyticsBase/reports/export',
        queryParameters: {'type': type, 'format': 'pdf'},
      );
      if (response.statusCode == 200 && response.data is Map) {
        final data = response.data as Map<String, dynamic>;
        // Le backend retourne l'URL du fichier PDF généré
        return data['url'] as String? ?? data['fileUrl'] as String? ?? '';
      }
      throw Exception('Export PDF failed: ${response.statusCode}');
    } on DioException catch (e, st) {
      AppLogger.error('ReportsRepository: exportReportPdf échoué', error: e, stackTrace: st);
      rethrow;
    }
  }

  @override
  Future<String> exportReportExcel(String type, {String format = 'excel'}) async {
    try {
      final response = await _apiClient.post(
        '$_analyticsBase/reports/export',
        queryParameters: {'type': type, 'format': format},
      );
      if (response.statusCode == 200 && response.data is Map) {
        final data = response.data as Map<String, dynamic>;
        // Le backend retourne l'URL du fichier Excel/CSV généré
        return data['url'] as String? ?? data['fileUrl'] as String? ?? '';
      }
      throw Exception('Export $format failed: ${response.statusCode}');
    } on DioException catch (e, st) {
      AppLogger.error('ReportsRepository: exportReportExcel échoué', error: e, stackTrace: st);
      rethrow;
    }
  }

  @override
  Future<void> scheduleReport({String? cronExpression}) async {
    try {
      final response = await _apiClient.post(
        '$_analyticsBase/reports/schedule',
        data: cronExpression != null ? {'cronExpression': cronExpression} : null,
      );
      if (response.statusCode != 200 && response.statusCode != 201 && response.statusCode != 204) {
        throw Exception('Schedule report failed: ${response.statusCode}');
      }
    } on DioException catch (e, st) {
      AppLogger.error('ReportsRepository: scheduleReport échoué', error: e, stackTrace: st);
      rethrow;
    }
  }

  @override
  Future<List<Map<String, dynamic>>> getScheduledReports() async {
    try {
      final response = await _apiClient.get('$_analyticsBase/reports/scheduled');
      if (response.statusCode == 200) {
        final data = response.data;
        if (data is List) {
          return data.map((e) => Map<String, dynamic>.from(e as Map)).toList();
        }
      }
      return [];
    } on DioException catch (e, st) {
      AppLogger.error('ReportsRepository: getScheduledReports échoué', error: e, stackTrace: st);
      return [];
    }
  }
}
