import 'package:em2rp/services/api_service.dart';
import 'package:em2rp/utils/debug_log.dart';

/// Repository pour gérer toutes les opérations sur les équipements.
class EquipmentRepository {
  final ApiService _apiService;

  EquipmentRepository(this._apiService);

  /// Récupère tous les équipements (avec masquage des prix selon permissions)
  Future<List<Map<String, dynamic>>> getEquipments() async {
    try {
      print('[EquipmentRepository] Calling getEquipments API...');
      final result = await _apiService.call('getEquipments', {});
      print('[EquipmentRepository] API call successful, parsing result...');
      final equipments = result['equipments'] as List<dynamic>?;
      if (equipments == null) {
        print('[EquipmentRepository] No equipments in result');
        return [];
      }
      print('[EquipmentRepository] Found ${equipments.length} equipments');
      return equipments.map((e) => e as Map<String, dynamic>).toList();
    } catch (e) {
      print('[EquipmentRepository] Error getting equipments: $e');
      throw Exception('Erreur lors de la récupération des équipements: $e');
    }
  }

  /// Récupère plusieurs équipements par leurs IDs
  Future<List<Map<String, dynamic>>> getEquipmentsByIds(
      List<String> equipmentIds) async {
    try {
      if (equipmentIds.isEmpty) return [];

      print(
          '[EquipmentRepository] Getting equipments by IDs: ${equipmentIds.length} items');
      final result = await _apiService.call('getEquipmentsByIds', {
        'equipmentIds': equipmentIds,
      });
      final equipments = result['equipments'] as List<dynamic>?;
      if (equipments == null) {
        print('[EquipmentRepository] No equipments in result');
        return [];
      }
      print('[EquipmentRepository] Found ${equipments.length} equipments by IDs');
      return equipments.map((e) => e as Map<String, dynamic>).toList();
    } catch (e) {
      print('[EquipmentRepository] Error getting equipments by IDs: $e');
      throw Exception('Erreur lors de la récupération des équipements: $e');
    }
  }

  /// Récupère les équipements avec pagination et filtrage
  Future<Map<String, dynamic>> getEquipmentsPaginated({
    int limit = 20,
    String? startAfter,
    String? category,
    String? status,
    String? searchQuery,
    String sortBy = 'id',
    String sortOrder = 'asc',
  }) async {
    try {
      final params = <String, dynamic>{
        'limit': limit,
        'sortBy': sortBy,
        'sortOrder': sortOrder,
      };

      if (startAfter != null) params['startAfter'] = startAfter;
      if (category != null) params['category'] = category;
      if (status != null) params['status'] = status;
      if (searchQuery != null && searchQuery.isNotEmpty) {
        params['searchQuery'] = searchQuery;
      }

      final result =
          await (_apiService as FirebaseFunctionsApiService).callPaginated(
        'getEquipmentsPaginated',
        params,
      );

      return {
        'equipments': (result['equipments'] as List<dynamic>?)
                ?.map((e) => e as Map<String, dynamic>)
                .toList() ??
            [],
        'hasMore': result['hasMore'] as bool? ?? false,
        'lastVisible': result['lastVisible'] as String?,
        'total': result['total'] as int? ?? 0,
      };
    } catch (e) {
      DebugLog.error('[EquipmentRepository] Error in getEquipmentsPaginated', e);
      throw Exception(
          'Erreur lors de la récupération paginée des équipements: $e');
    }
  }

  /// Crée un équipement
  Future<void> createEquipment(
      String equipmentId, Map<String, dynamic> data) async {
    try {
      final equipmentData = Map<String, dynamic>.from(data);
      equipmentData['id'] = equipmentId;

      await _apiService.call('createEquipment', equipmentData);
    } catch (e) {
      throw Exception('Erreur lors de la création de l\'équipement: $e');
    }
  }

  /// Met à jour un équipement
  Future<void> updateEquipment(
      String equipmentId, Map<String, dynamic> data) async {
    try {
      await _apiService.call('updateEquipment', {
        'equipmentId': equipmentId,
        'data': data,
      });
    } catch (e) {
      throw Exception('Erreur lors de la mise à jour de l\'équipement: $e');
    }
  }

  /// Supprime un équipement
  Future<void> deleteEquipment(String equipmentId,
      {bool forceDelete = false}) async {
    try {
      await _apiService.call('deleteEquipment', {
        'equipmentId': equipmentId,
        'forceDelete': forceDelete,
      });
    } on ApiException {
      rethrow;
    } catch (e) {
      throw Exception('Erreur lors de la suppression de l\'équipement: $e');
    }
  }

  /// Met à jour uniquement le statut d'un équipement
  Future<void> updateEquipmentStatusOnly({
    required String equipmentId,
    String? status,
    int? availableQuantity,
  }) async {
    try {
      final data = <String, dynamic>{'equipmentId': equipmentId};

      if (status != null) data['status'] = status;
      if (availableQuantity != null) {
        data['availableQuantity'] = availableQuantity;
      }

      await _apiService.call('updateEquipmentStatusOnly', data);
    } catch (e) {
      throw Exception(
          'Erreur lors de la mise à jour du statut de l\'équipement: $e');
    }
  }

  /// Recherche rapide (autocomplétion)
  Future<List<Map<String, dynamic>>> quickSearch(
    String query, {
    int limit = 10,
    bool includeEquipments = true,
    bool includeContainers = true,
  }) async {
    try {
      return await (_apiService as FirebaseFunctionsApiService).quickSearch(
        query,
        limit: limit,
        includeEquipments: includeEquipments,
        includeContainers: includeContainers,
      );
    } catch (e) {
      DebugLog.error('[EquipmentRepository] Error in quickSearch', e);
      return [];
    }
  }

  /// Recherche des équipements pour l'assistant IA avec fallback paginé.
  Future<List<Map<String, dynamic>>> searchEquipmentsForAssistant({
    required String query,
    int limit = 12,
  }) async {
    final normalizedQuery = query.trim();
    if (normalizedQuery.isEmpty) {
      return [];
    }

    try {
      final quickResults = await quickSearch(
        normalizedQuery,
        limit: limit,
        includeEquipments: true,
        includeContainers: false,
      );

      final equipmentResults = quickResults
          .where((item) =>
              (item['type']?.toString().toLowerCase() ?? '') == 'equipment')
          .map(_normalizeAssistantEquipment)
          .toList();

      if (equipmentResults.isNotEmpty) {
        return equipmentResults;
      }

      final paginated = await getEquipmentsPaginated(
        limit: limit,
        searchQuery: normalizedQuery,
        sortBy: 'id',
        sortOrder: 'asc',
      );

      final equipments =
          paginated['equipments'] as List<Map<String, dynamic>>? ?? [];
      return equipments.map(_normalizeAssistantEquipment).toList();
    } catch (e) {
      DebugLog.error('[EquipmentRepository] Error in searchEquipmentsForAssistant', e);
      throw Exception('Erreur lors de la recherche de matériel: $e');
    }
  }

  /// Vérifie la disponibilité d'un équipement dans un format normalisé pour l'IA.
  Future<Map<String, dynamic>> checkEquipmentAvailabilityForAssistant({
    required String equipmentId,
    required DateTime startDate,
    required DateTime endDate,
    String? excludeEventId,
  }) async {
    try {
      final result = await checkEquipmentAvailability(
        equipmentId: equipmentId,
        startDate: startDate,
        endDate: endDate,
        excludeEventId: excludeEventId,
      );

      final available = result['available'] as bool? ?? true;
      final conflicts = (result['conflicts'] as List<dynamic>? ?? const [])
          .whereType<Map<String, dynamic>>()
          .map((conflict) {
        final eventData =
            conflict['eventData'] as Map<String, dynamic>? ?? const {};
        final eventName =
            (eventData['Name'] ?? conflict['eventName'] ?? '').toString();
        return {
          'eventId': conflict['eventId']?.toString() ?? '',
          'eventName': eventName,
          'overlapDays': conflict['overlapDays'] as int? ?? 0,
        };
      }).toList();

      return {
        'equipmentId': equipmentId,
        'available': available,
        'conflictCount': conflicts.length,
        'conflicts': conflicts,
      };
    } catch (e) {
      DebugLog.error(
          '[EquipmentRepository] Error in checkEquipmentAvailabilityForAssistant', e);
      throw Exception('Erreur lors de la vérification de disponibilité: $e');
    }
  }

  /// Vérifie la disponibilité d'un équipement
  Future<Map<String, dynamic>> checkEquipmentAvailability({
    required String equipmentId,
    required DateTime startDate,
    required DateTime endDate,
    String? excludeEventId,
  }) async {
    try {
      final result = await _apiService.call('checkEquipmentAvailability', {
        'equipmentId': equipmentId,
        'startDate': startDate.toIso8601String(),
        'endDate': endDate.toIso8601String(),
        if (excludeEventId != null) 'excludeEventId': excludeEventId,
      });
      return result;
    } catch (e) {
      throw Exception('Erreur lors de la vérification de disponibilité: $e');
    }
  }

  /// Récupère tous les IDs d'équipements et conteneurs en conflit pour une période
  /// Optimisé : une seule requête au lieu d'une par équipement
  Future<Map<String, dynamic>> getConflictingEquipmentIds({
    required DateTime startDate,
    required DateTime endDate,
    String? excludeEventId,
    int installationTime = 0,
    int disassemblyTime = 0,
  }) async {
    try {
      final result = await _apiService.call('getConflictingEquipmentIds', {
        'startDate': startDate.toIso8601String(),
        'endDate': endDate.toIso8601String(),
        if (excludeEventId != null) 'excludeEventId': excludeEventId,
        'installationTime': installationTime,
        'disassemblyTime': disassemblyTime,
      });
      return result;
    } catch (e) {
      throw Exception(
          'Erreur lors de la récupération des équipements en conflit: $e');
    }
  }

  Map<String, dynamic> _normalizeAssistantEquipment(Map<String, dynamic> item) {
    return {
      'id': (item['id'] ?? '').toString(),
      'name': (item['name'] ?? item['id'] ?? '').toString(),
      'category': (item['category'] ?? '').toString(),
      'status': (item['status'] ?? '').toString(),
      'brand': item['brand']?.toString(),
      'model': item['model']?.toString(),
      'availableQuantity': item['availableQuantity'],
      'totalQuantity': item['totalQuantity'],
    };
  }

  /// Récupère toutes les maintenances
  Future<List<Map<String, dynamic>>> getMaintenances(
      {String? equipmentId}) async {
    try {
      final data = <String, dynamic>{};
      if (equipmentId != null) data['equipmentId'] = equipmentId;

      final result = await _apiService.call('getMaintenances', data);
      final maintenances = result['maintenances'] as List<dynamic>?;
      if (maintenances == null) return [];
      return maintenances.map((e) => e as Map<String, dynamic>).toList();
    } catch (e) {
      throw Exception('Erreur lors de la récupération des maintenances: $e');
    }
  }

  /// Supprime une maintenance
  Future<void> deleteMaintenance(String maintenanceId) async {
    try {
      await _apiService
          .call('deleteMaintenance', {'maintenanceId': maintenanceId});
    } catch (e) {
      throw Exception('Erreur lors de la suppression de la maintenance: $e');
    }
  }
}
