import 'package:em2rp/models/equipment_model.dart';
import 'package:em2rp/models/maintenance_model.dart';
import 'package:em2rp/models/container_model.dart';
import 'package:em2rp/services/api_service.dart';
import 'package:em2rp/services/data_service.dart';
import 'package:em2rp/services/maintenance_service.dart';

class EquipmentService {
  final ApiService _apiService = apiService;
  final DataService _dataService = DataService(apiService);

  // ============================================================================
  // Helper privée - Charge TOUS les équipements avec pagination
  // ============================================================================

  /// Charge tous les équipements en utilisant la pagination
  Future<List<Map<String, dynamic>>> _getAllEquipmentsPaginated() async {
    final allEquipments = <Map<String, dynamic>>[];
    String? lastVisible;
    bool hasMore = true;

    while (hasMore) {
      final result = await _dataService.getEquipmentsPaginated(
        limit: 100,
        startAfter: lastVisible,
        sortBy: 'id',
        sortOrder: 'asc',
      );

      final equipments = result['equipments'] as List<dynamic>;
      allEquipments.addAll(equipments.cast<Map<String, dynamic>>());

      hasMore = result['hasMore'] as bool? ?? false;
      lastVisible = result['lastVisible'] as String?;
    }

    return allEquipments;
  }

  // ============================================================================
  // CRUD Operations - Utilise le backend sécurisé
  // ============================================================================

  /// Créer un nouvel équipement (via Cloud Function)
  Future<void> createEquipment(EquipmentModel equipment) async {
    try {
      if (equipment.id.isEmpty) {
        throw Exception('L\'ID de l\'équipement est requis pour la création');
      }

      final data = equipment.toMap();
      data['id'] = equipment.id; // S'assurer que l'ID est inclus

      await _apiService.call('createEquipment', data);
    } catch (e) {
      print('Error creating equipment: $e');
      rethrow;
    }
  }

  /// Mettre à jour un équipement (via Cloud Function)
  Future<void> updateEquipment(String id, Map<String, dynamic> data) async {
    try {
      if (data.isEmpty) {
        throw Exception('Aucune donnée à mettre à jour');
      }

      await _apiService.call('updateEquipment', {
        'equipmentId': id,
        'data': data,
      });
    } catch (e) {
      print('Error updating equipment: $e');
      rethrow;
    }
  }

  /// Supprimer un équipement (via Cloud Function)
  Future<void> deleteEquipment(String id) async {
    try {
      await _apiService.call('deleteEquipment', {'equipmentId': id});
    } catch (e) {
      print('Error deleting equipment: $e');
      rethrow;
    }
  }

  // ============================================================================
  // READ Operations - Utilise Firestore streams (temps réel)
  // ============================================================================

  /// Récupérer un équipement par ID
  Future<EquipmentModel?> getEquipmentById(String id) async {
    try {
      final equipmentsData = await _dataService.getEquipmentsByIds([id]);
      if (equipmentsData.isEmpty) return null;

      return EquipmentModel.fromMap(equipmentsData.first, id);
    } catch (e) {
      print('Error getting equipment: $e');
      rethrow;
    }
  }

  /// Récupérer les équipements avec filtres
  Future<List<EquipmentModel>> getEquipment({
    EquipmentCategory? category,
    EquipmentStatus? status,
    String? model,
    String? searchQuery,
  }) async {
    try {
      final equipmentsData = await _getAllEquipmentsPaginated();

      var equipmentList = equipmentsData
          .map((data) {
            final id = data['id'] as String;
            return EquipmentModel.fromMap(data, id);
          })
          .toList();

      // Filtres côté client
      if (category != null) {
        equipmentList = equipmentList
            .where((e) => e.category == category)
            .toList();
      }

      if (status != null) {
        equipmentList = equipmentList
            .where((e) => e.status == status)
            .toList();
      }

      if (model != null && model.isNotEmpty) {
        equipmentList = equipmentList
            .where((e) => e.model == model)
            .toList();
      }

      if (searchQuery != null && searchQuery.isNotEmpty) {
        final lowerSearch = searchQuery.toLowerCase();
        equipmentList = equipmentList.where((equipment) {
          return equipment.name.toLowerCase().contains(lowerSearch) ||
                 (equipment.model?.toLowerCase().contains(lowerSearch) ?? false) ||
                 equipment.id.toLowerCase().contains(lowerSearch);
        }).toList();
      }

      return equipmentList;
    } catch (e) {
      print('Error getting equipment: $e');
      rethrow;
    }
  }

  // ============================================================================
  // Availability & Stock Management - Logique métier côté client
  // ============================================================================

  /// Vérifier la disponibilité d'un équipement pour une période donnée
  Future<List<Map<String, dynamic>>> checkAvailability(
    String equipmentId,
    DateTime startDate,
    DateTime endDate,
  ) async {
    try {
      final response = await _apiService.call('checkEquipmentAvailability', {
        'equipmentId': equipmentId,
        'startDate': startDate.toIso8601String(),
        'endDate': endDate.toIso8601String(),
      });

      final conflicts = (response['conflicts'] as List?)
          ?.map((c) => c as Map<String, dynamic>)
          .toList() ?? [];

      return conflicts;
    } catch (e) {
      print('Error checking availability: $e');
      rethrow;
    }
  }

  /// Trouver des alternatives (même modèle) disponibles
  Future<List<EquipmentModel>> findAlternatives(
    String model,
    DateTime startDate,
    DateTime endDate,
  ) async {
    try {
      final response = await _apiService.call('findAlternativeEquipment', {
        'model': model,
        'startDate': startDate.toIso8601String(),
        'endDate': endDate.toIso8601String(),
      });

      final alternatives = (response['alternatives'] as List?)
          ?.map((a) {
            final map = a as Map<String, dynamic>;
            final id = map['id'] as String;
            return EquipmentModel.fromMap(map, id);
          })
          .toList() ?? [];

      return alternatives;
    } catch (e) {
      print('Error finding alternatives: $e');
      rethrow;
    }
  }

  /// Mettre à jour le stock d'un consommable/câble
  Future<void> updateStock(String id, int quantityChange) async {
    try {
      final equipment = await getEquipmentById(id);
      if (equipment == null) {
        throw Exception('Equipment not found');
      }

      if (!equipment.hasQuantity) {
        throw Exception('Equipment does not have quantity tracking');
      }

      final newAvailableQuantity = (equipment.availableQuantity ?? 0) + quantityChange;

      await updateEquipment(id, {
        'availableQuantity': newAvailableQuantity,
      });

      // Vérifier si le seuil critique est atteint
      if (equipment.criticalThreshold != null &&
          newAvailableQuantity <= equipment.criticalThreshold!) {
        await _createLowStockAlert(equipment);
      }
    } catch (e) {
      print('Error updating stock: $e');
      rethrow;
    }
  }

  /// Créer une alerte de stock faible
  Future<void> _createLowStockAlert(EquipmentModel equipment) async {
    try {
      // Note: Cette fonction pourrait utiliser une Cloud Function dédiée dans le futur
      // Pour l'instant, on utilise l'API directement pour éviter de créer trop de fonctions
      // Cette méthode est appelée rarement et en arrière-plan
      await _apiService.call('createAlert', {
        'type': 'LOW_STOCK',
        'title': 'Stock critique',
        'message': 'Stock critique pour ${equipment.name} (${equipment.model ?? ""}): ${equipment.availableQuantity}/${equipment.criticalThreshold}',
        'severity': 'HIGH',
        'equipmentId': equipment.id,
      });
    } catch (e) {
      print('Error creating low stock alert: $e');
      // Ne pas rethrow pour ne pas bloquer le processus
    }
  }

  /// Générer les données du QR code (ID de l'équipement)
  String generateQRCodeData(String equipmentId) {
    // Pour l'instant, on retourne simplement l'ID
    // On pourrait aussi générer une URL complète : https://app.em2events.fr/equipment/$equipmentId
    return equipmentId;
  }

  /// Récupérer les modèles filtrés par marque
  Future<List<String>> getModelsByBrand(String brand) async {
    try {
      final equipmentsData = await _getAllEquipmentsPaginated();
      final models = <String>{};

      for (var data in equipmentsData) {
        if (data['brand'] == brand) {
          final model = data['model'] as String?;
          if (model != null && model.isNotEmpty) {
            models.add(model);
          }
        }
      }

      return models.toList()..sort();
    } catch (e) {
      print('Error getting models by brand: $e');
      rethrow;
    }
  }

  /// Récupérer les sous-catégories filtrées par catégorie
  Future<List<String>> getSubCategoriesByCategory(EquipmentCategory category) async {
    try {
      final equipmentsData = await _getAllEquipmentsPaginated();
      final subCategories = <String>{};

      final categoryString = equipmentCategoryToString(category);

      for (var data in equipmentsData) {
        if (data['category'] == categoryString) {
          final subCategory = data['subCategory'] as String?;
          if (subCategory != null && subCategory.isNotEmpty) {
            subCategories.add(subCategory);
          }
        }
      }

      return subCategories.toList()..sort();
    } catch (e) {
      print('Error getting subcategories by category: $e');
      rethrow;
    }
  }

  /// Vérifier si un ID existe déjà
  Future<bool> isIdUnique(String id) async {
    try {
      final equipment = await getEquipmentById(id);
      return equipment == null;
    } catch (e) {
      print('Error checking ID uniqueness: $e');
      rethrow;
    }
  }

  /// Récupérer toutes les boîtes/containers disponibles
  Future<List<ContainerModel>> getBoxes() async {
    try {
      final containersData = await _dataService.getContainers();

      final boxes = <ContainerModel>[];
      for (var data in containersData) {
        final id = data['id'] as String;
        final container = ContainerModel.fromMap(data, id);
        boxes.add(container);
      }

      return boxes;
    } catch (e) {
      print('Error getting boxes: $e');
      rethrow;
    }
  }

  /// Récupérer plusieurs équipements par leurs IDs
  Future<List<EquipmentModel>> getEquipmentsByIds(List<String> ids) async {
    try {
      if (ids.isEmpty) return [];

      final equipmentsData = await _dataService.getEquipmentsByIds(ids);

      return equipmentsData
          .map((data) {
            final id = data['id'] as String;
            return EquipmentModel.fromMap(data, id);
          })
          .toList();
    } catch (e) {
      print('Error getting equipments by IDs: $e');
      rethrow;
    }
  }

  /// Récupérer les maintenances pour un équipement
  /// Note: Cette méthode est maintenant déléguée au MaintenanceService
  /// pour éviter la duplication de code
  Future<List<MaintenanceModel>> getMaintenancesForEquipment(String equipmentId) async {
    try {
      // Déléguer au MaintenanceService qui utilise déjà les Cloud Functions
      final maintenanceService = MaintenanceService();
      return await maintenanceService.getMaintenancesByEquipment(equipmentId);
    } catch (e) {
      print('Error getting maintenances for equipment: $e');
      rethrow;
    }
  }
}

