import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'dart:math' as math;
import 'dart:async';
import 'package:geosector_app/presentation/widgets/mapbox_map.dart';
import 'package:geosector_app/presentation/widgets/app_scaffold.dart';
import 'package:geosector_app/core/constants/app_keys.dart';
import 'package:geosector_app/core/services/location_service.dart';
import 'package:geosector_app/core/data/models/sector_model.dart';
import 'package:geosector_app/core/data/models/passage_model.dart';
import 'package:geosector_app/core/data/models/user_sector_model.dart';
import 'package:geosector_app/presentation/dialogs/sector_dialog.dart';
import 'package:geosector_app/core/repositories/sector_repository.dart';
import 'package:geosector_app/core/repositories/passage_repository.dart';
import 'package:geosector_app/core/services/current_amicale_service.dart';
import 'package:geosector_app/core/services/current_user_service.dart';
import 'package:geosector_app/core/repositories/operation_repository.dart';
import 'package:geosector_app/presentation/widgets/passage_map_dialog.dart';
import 'package:geosector_app/presentation/widgets/grouped_passages_dialog.dart';
import 'package:go_router/go_router.dart';

/// Page de carte globale pour admin et utilisateurs
/// Adapte automatiquement ses fonctionnalités selon le rôle
class MapPage extends StatelessWidget {
  const MapPage({super.key});

  @override
  Widget build(BuildContext context) {
    debugPrint('🔄 MapPage.build() appelé');
    // Utiliser le mode d'affichage au lieu du rôle réel
    final isAdmin = CurrentUserService.instance.shouldShowAdminUI;

    // Obtenir l'index de navigation selon la route actuelle
    final currentRoute = GoRouterState.of(context).uri.toString();
    final selectedIndex = NavigationHelper.getIndexFromRoute(currentRoute, isAdmin);

    return AppScaffold(
      selectedIndex: selectedIndex,
      pageTitle: 'Carte',
      showBackground: false, // Pas de fond inutile, la carte prend tout l'espace
      body: const MapPageContent(),
    );
  }
}

/// Contenu de la page carte (séparé pour réutilisabilité)
class MapPageContent extends StatefulWidget {
  const MapPageContent({super.key});

  @override
  State<MapPageContent> createState() => _MapPageContentState();
}

// Enum pour les modes de la carte
enum MapMode {
  view, // Mode vue normale
  drawing, // Mode création de secteur (admin seulement)
  editing, // Mode modification de secteur (admin seulement)
  deleting, // Mode suppression de secteur (admin seulement)
}

class _MapPageContentState extends State<MapPageContent> {
  // Contrôleur de carte
  final MapController _mapController = MapController();

  // Position actuelle et zoom
  LatLng _currentPosition =
      const LatLng(48.117266, -1.6777926); // Position initiale sur Rennes
  double _currentZoom = 15.0; // Zoom par défaut (sera écrasé par Hive si disponible)

  // Données des secteurs et passages
  final List<Map<String, dynamic>> _sectors = [];
  final List<Map<String, dynamic>> _passages = [];

  // Affichage éphémère du niveau de zoom
  bool _showZoomIndicator = false;
  Timer? _zoomIndicatorTimer;

  // Timer pour debouncer le setState et la sauvegarde lors du déplacement de carte
  Timer? _mapMoveDebounceTimer;

  // États
  MapMode _mapMode = MapMode.view;
  int? _selectedSectorId;
  List<DropdownMenuItem<int?>> _sectorItems = [];

  // Filtre de type de passage (null = aucun, -1 = tous, autre = type spécifique)
  int? _selectedPassageTypeFilter;
  List<DropdownMenuItem<int?>> _passageTypeItems = [];

  // États pour le mode dessin
  List<LatLng> _drawingPoints = [];
  int? _draggingPointIndex; // Index du point en cours de déplacement
  LatLng? _originalDragPosition; // Position originale avant le drag

  // États pour le magnétisme
  LatLng? _snapPoint; // Point d'accrochage détecté
  static const double _snapDistance = 20.0; // Distance de magnétisme en mètres

  // État pour les midpoints
  int? _hoveredMidpointIndex; // Index du midpoint survolé

  // États pour le mode édition
  SectorModel? _selectedSectorForEdit;
  List<LatLng> _editingPoints = [];
  final Map<int, LatLng> _originalPoints = {}; // Pour annuler les modifications
  int? _hoveredPointIndex; // Index du point principal survolé

  // État pour le mode suppression
  int? _sectorToDeleteId;
  int? _hoveredSectorId; // ID du secteur survolé en mode suppression

  // État pour le survol en mode édition
  int? _hoveredSectorIdForEdit; // ID du secteur survolé en mode édition

  // État pour bloquer le drag de la carte pendant le déplacement des points
  bool _isDraggingPoint = false;

  // État pour bloquer la sauvegarde du zoom lors du centrage sur secteur
  bool _isCenteringOnSector = false;

  // Source des tuiles de la carte (IGN Plan ou IGN Ortho)
  TileSource _tileSource = TileSource.ignPlan;

  // Comptages des secteurs (calculés uniquement lors de création/modification de secteurs)
  Map<int, int> _sectorPassageCount = {};
  Map<int, int> _sectorMemberCount = {};

  // Référence à la boîte Hive pour les paramètres
  late Box _settingsBox;

  // Listener pour les changements de paramètres
  late ValueListenable<Box<dynamic>> _settingsListenable;

  // Vérifier si l'utilisateur est admin (utilise le mode d'affichage)
  bool get isAdmin {
    return CurrentUserService.instance.shouldShowAdminUI;
  }

  // Vérifier si l'utilisateur peut modifier les secteurs
  bool get canEditSectors => isAdmin;

  @override
  void initState() {
    super.initState();
    _initSettings().then((_) {
      _loadSectors();
      _loadPassages();

      // Écouter les changements du secteur sélectionné
      _settingsListenable = _settingsBox.listenable(keys: ['selectedSectorId']);
      _settingsListenable.addListener(_onSectorSelectionChanged);

      // Centrer sur le secteur si déjà sélectionné (navigation depuis home_page)
      WidgetsBinding.instance.addPostFrameCallback((_) {
        if (_selectedSectorId != null && _sectors.any((s) => s['id'] == _selectedSectorId)) {
          debugPrint('🎯 MapPage: Secteur présélectionné détecté ($_selectedSectorId), centrage...');
          _centerMapOnSpecificSector(_selectedSectorId!);
        }
      });
    });
  }

  // Initialiser la boîte de paramètres et charger les préférences
  Future<void> _initSettings() async {
    // Ouvrir la boîte de paramètres si elle n'est pas déjà ouverte
    if (!Hive.isBoxOpen(AppKeys.settingsBoxName)) {
      _settingsBox = await Hive.openBox(AppKeys.settingsBoxName);
    } else {
      _settingsBox = Hive.box(AppKeys.settingsBoxName);
    }

    // Charger le secteur sélectionné
    _selectedSectorId = _settingsBox.get('selectedSectorId');

    // Charger le filtre de type de passage
    // Admin : par défaut null = aucun passage
    // User : par défaut -1 = tous les passages (car pas d'accès à la combobox)
    _selectedPassageTypeFilter = _settingsBox.get('selectedPassageTypeFilter');
    if (_selectedPassageTypeFilter == null && !isAdmin) {
      _selectedPassageTypeFilter = -1; // Tous les passages pour les users
    }

    // Charger la position et le zoom
    final double? savedLat = _settingsBox.get('mapLat');
    final double? savedLng = _settingsBox.get('mapLng');
    final double? savedZoom = _settingsBox.get('mapZoom');

    if (savedLat != null && savedLng != null) {
      _currentPosition = LatLng(savedLat, savedLng);
    } else {
      // Essayer d'utiliser les coordonnées GPS de l'amicale
      final amicale = CurrentAmicaleService.instance.currentAmicale;
      if (amicale != null && amicale.gpsLat.isNotEmpty && amicale.gpsLng.isNotEmpty) {
        try {
          final lat = double.parse(amicale.gpsLat);
          final lng = double.parse(amicale.gpsLng);
          _currentPosition = LatLng(lat, lng);
          debugPrint('📍 MapPage: Position centrée sur l\'amicale ($lat, $lng)');
        } catch (e) {
          // Si parsing échoue, garder la position Rennes par défaut
          debugPrint('⚠️ MapPage: Erreur parsing GPS amicale: $e');
        }
      }
      // Sinon, _currentPosition garde sa valeur par défaut (Rennes)
    }

    if (savedZoom != null) {
      _currentZoom = savedZoom;
      debugPrint('🔍 MapPage: Zoom chargé depuis Hive = $_currentZoom');
    } else {
      // Zoom par défaut à 15 si rien n'est sauvegardé
      _currentZoom = 15.0;
      _settingsBox.put('mapZoom', 15.0);
      debugPrint('🔍 MapPage: Aucun zoom sauvegardé, utilisation du défaut = 15.0');
    }

    // Charger la source des tuiles (IGN Plan par défaut)
    final savedTileSource = _settingsBox.get('mapTileSource');
    if (savedTileSource != null) {
      _tileSource = TileSource.values.firstWhere(
        (t) => t.name == savedTileSource,
        orElse: () => TileSource.ignPlan,
      );
      debugPrint('🗺️ MapPage: Source tuiles chargée = $_tileSource');
    }
  }

  // Méthode pour gérer les changements de sélection de secteur
  void _onSectorSelectionChanged() {
    final newSectorId = _settingsBox.get('selectedSectorId');
    if (newSectorId != null && newSectorId != _selectedSectorId) {
      setState(() {
        _selectedSectorId = newSectorId;
      });

      // Recharger les passages pour le nouveau secteur
      _loadPassages();

      // Attendre que le build soit fait puis centrer sur le secteur
      WidgetsBinding.instance.addPostFrameCallback((_) {
        if (_sectors.any((s) => s['id'] == _selectedSectorId)) {
          _centerMapOnSpecificSector(_selectedSectorId!);
        }
      });
    }
  }

  @override
  void dispose() {
    _settingsListenable.removeListener(_onSectorSelectionChanged);
    _zoomIndicatorTimer?.cancel();
    _mapMoveDebounceTimer?.cancel();
    _mapController.dispose();
    super.dispose();
  }

  // Afficher temporairement l'indicateur de zoom
  void _showZoomIndicatorTemporarily() {
    // Annuler le timer précédent s'il existe
    _zoomIndicatorTimer?.cancel();

    // Afficher l'indicateur
    if (mounted) {
      setState(() {
        _showZoomIndicator = true;
      });
    }

    // Masquer après 2 secondes
    _zoomIndicatorTimer = Timer(const Duration(seconds: 2), () {
      if (mounted) {
        setState(() {
          _showZoomIndicator = false;
        });
      }
    });
  }

  // Sauvegarder les paramètres utilisateur
  void _saveSettings() {
    // Sauvegarder le secteur sélectionné
    if (_selectedSectorId != null) {
      _settingsBox.put('selectedSectorId', _selectedSectorId);
    }

    // Sauvegarder la position
    _settingsBox.put('mapLat', _currentPosition.latitude);
    _settingsBox.put('mapLng', _currentPosition.longitude);

    // Sauvegarder le zoom SAUF si on est en train de centrer sur un secteur
    if (!_isCenteringOnSector) {
      _settingsBox.put('mapZoom', _currentZoom);
    }
  }

  // Mettre à jour les comptages des secteurs (passages et membres)
  void _updateSectorCounts() {
    setState(() {
      _sectorPassageCount = _countPassagesBySector();
      _sectorMemberCount = _countMembersBySector();
    });
  }

  // Charger les secteurs depuis la boîte Hive (avec setState)
  void _loadSectors() {
    // L'API retourne déjà les secteurs filtrés selon le rôle (admin ou user)
    try {
      final sectorsBox = Hive.box<SectorModel>(AppKeys.sectorsBoxName);
      final sectors = sectorsBox.values.toList();

      setState(() {
        _sectors.clear();

        for (final sector in sectors) {
          final List<List<double>> coordinates = sector.getCoordinates();
          final List<LatLng> points =
              coordinates.map((coord) => LatLng(coord[0], coord[1])).toList();

          if (points.isNotEmpty) {
            _sectors.add({
              'id': sector.id,
              'name': sector.libelle,
              'color': _hexToColor(sector.color),
              'points': points,
            });
          }
        }

        // Mettre à jour les items de la combobox de secteurs
        _updateSectorItems();

        // Mettre à jour les items de la combobox de types de passage
        _updatePassageTypeItems();
      });

      // Mettre à jour les comptages des secteurs après chargement
      _updateSectorCounts();
    } catch (e) {
      debugPrint('Erreur lors du chargement des secteurs: $e');
    }
  }

  // Charger les passages depuis la boîte (pour ValueListenableBuilder)
  void _loadPassagesFromBox(Box<PassageModel> passagesBox) {
    try {
      // Si le filtre de type de passage est null (Aucun passage), ne rien charger
      if (_selectedPassageTypeFilter == null) {
        if (_passages.isNotEmpty) {
          setState(() {
            _passages.clear();
          });
        }
        return;
      }

      final List<Map<String, dynamic>> newPassages = [];

      for (var i = 0; i < passagesBox.length; i++) {
        final passage = passagesBox.getAt(i);
        if (passage != null) {
          final lat = double.tryParse(passage.gpsLat);
          final lng = double.tryParse(passage.gpsLng);

          // Filtrer par secteur si un secteur est sélectionné
          if (_selectedSectorId != null &&
              passage.fkSector != _selectedSectorId) {
            continue;
          }

          // Filtrer par type de passage si un type spécifique est sélectionné
          // -1 signifie "Tous les passages", donc pas de filtre
          if (_selectedPassageTypeFilter != -1 &&
              passage.fkType != _selectedPassageTypeFilter) {
            continue;
          }

          if (lat != null && lng != null) {
            Color passageColor = Colors.grey;

            if (AppKeys.typesPassages.containsKey(passage.fkType)) {
              // Déterminer la couleur selon le type et nbPassages
              if (passage.fkType == 2) {
                // Type 2 (À finaliser) : adapter la couleur selon nbPassages
                final typeInfo = AppKeys.typesPassages[passage.fkType]!;
                if (passage.nbPassages == 0) {
                  passageColor = Color(typeInfo['couleur1'] as int);
                } else if (passage.nbPassages == 1) {
                  passageColor = Color(typeInfo['couleur2'] as int);
                } else {
                  // nbPassages > 1
                  passageColor = Color(typeInfo['couleur3'] as int);
                }
              } else {
                // Autres types : utiliser couleur1 par défaut
                final colorValue =
                    AppKeys.typesPassages[passage.fkType]!['couleur1'] as int;
                passageColor = Color(colorValue);
              }

              newPassages.add({
                'id': passage.id,
                'position': LatLng(lat, lng),
                'type': passage.fkType,
                'color': passageColor,
                'model': passage,
              });
            }
          }
        }
      }

      // Ne faire setState QUE si les données ont vraiment changé
      if (mounted && !_arePassagesEqual(_passages, newPassages)) {
        setState(() {
          _passages.clear();
          _passages.addAll(newPassages);
        });
      }
    } catch (e) {
      debugPrint('Erreur lors du chargement des passages: $e');
    }
  }

  // Comparer deux listes de passages pour éviter les setState inutiles
  bool _arePassagesEqual(List<Map<String, dynamic>> oldPassages, List<Map<String, dynamic>> newPassages) {
    if (oldPassages.length != newPassages.length) return false;

    // Créer des clés uniques incluant ID + fkType pour détecter les changements de type
    // (important pour le gradient des immeubles qui dépend du fkType)
    final oldKeys = oldPassages.map((p) {
      final model = p['model'] as PassageModel;
      return '${model.id}_${model.fkType}';
    }).toSet();

    final newKeys = newPassages.map((p) {
      final model = p['model'] as PassageModel;
      return '${model.id}_${model.fkType}';
    }).toSet();

    return oldKeys.length == newKeys.length && oldKeys.containsAll(newKeys);
  }

  // Charger les passages depuis la boîte Hive (avec setState)
  void _loadPassages() {
    // L'API retourne déjà les passages filtrés selon le rôle (admin ou user)
    try {
      // Si le filtre de type de passage est null (Aucun passage), ne rien charger
      if (_selectedPassageTypeFilter == null) {
        setState(() {
          _passages.clear();
        });
        return;
      }

      // Récupérer la boîte des passages
      final passagesBox = Hive.box<PassageModel>(AppKeys.passagesBoxName);

      // Créer une nouvelle liste temporaire
      final List<Map<String, dynamic>> newPassages = [];

      // Parcourir tous les passages dans la boîte
      for (var i = 0; i < passagesBox.length; i++) {
        final passage = passagesBox.getAt(i);
        if (passage != null) {
          // Vérifier si les coordonnées GPS sont valides
          final lat = double.tryParse(passage.gpsLat);
          final lng = double.tryParse(passage.gpsLng);

          // Filtrer par secteur si un secteur est sélectionné
          if (_selectedSectorId != null &&
              passage.fkSector != _selectedSectorId) {
            continue;
          }

          // Filtrer par type de passage si un type spécifique est sélectionné
          // -1 signifie "Tous les passages", donc pas de filtre
          if (_selectedPassageTypeFilter != -1 &&
              passage.fkType != _selectedPassageTypeFilter) {
            continue;
          }

          if (lat != null && lng != null) {
            // Obtenir la couleur du type de passage
            Color passageColor = Colors.grey; // Couleur par défaut

            // Vérifier si le type de passage existe dans AppKeys.typesPassages
            if (AppKeys.typesPassages.containsKey(passage.fkType)) {
              // Déterminer la couleur selon le type et nbPassages
              if (passage.fkType == 2) {
                // Type 2 (À finaliser) : adapter la couleur selon nbPassages
                final typeInfo = AppKeys.typesPassages[passage.fkType]!;
                if (passage.nbPassages == 0) {
                  passageColor = Color(typeInfo['couleur1'] as int);
                } else if (passage.nbPassages == 1) {
                  passageColor = Color(typeInfo['couleur2'] as int);
                } else {
                  // nbPassages > 1
                  passageColor = Color(typeInfo['couleur3'] as int);
                }
              } else {
                // Autres types : utiliser couleur1 par défaut
                final colorValue =
                    AppKeys.typesPassages[passage.fkType]!['couleur1'] as int;
                passageColor = Color(colorValue);
              }

              // Ajouter le passage à la liste temporaire
              newPassages.add({
                'id': passage.id,
                'position': LatLng(lat, lng),
                'type': passage.fkType,
                'color': passageColor,
                'model': passage, // Ajouter le modèle complet
              });
            }
          }
        }
      }

      // Mettre à jour la liste des passages dans l'état
      setState(() {
        _passages.clear();
        _passages.addAll(newPassages);
      });
    } catch (e) {
      debugPrint('Erreur lors du chargement des passages: $e');
    }
  }

  // Convertir une couleur hexadécimale en Color
  Color _hexToColor(String hexColor) {
    // Supprimer le # si présent
    final String colorStr =
        hexColor.startsWith('#') ? hexColor.substring(1) : hexColor;

    // Ajouter FF pour l'opacité si nécessaire (6 caractères -> 8 caractères)
    final String fullColorStr = colorStr.length == 6 ? 'FF$colorStr' : colorStr;

    // Convertir en entier et créer la couleur
    return Color(int.parse(fullColorStr, radix: 16));
  }

  // Assombrir une couleur pour les labels
  Color _darkenColor(Color color, [double amount = 0.3]) {
    assert(amount >= 0 && amount <= 1);

    final hsl = HSLColor.fromColor(color);
    final hslDark = hsl.withLightness((hsl.lightness - amount).clamp(0.0, 1.0));

    return hslDark.toColor();
  }

  // Centrer la carte sur tous les secteurs (sans changer le zoom)
  void _centerMapOnSectors() {
    if (_sectors.isEmpty) return;

    // Trouver les limites de tous les secteurs
    double minLat = 90.0;
    double maxLat = -90.0;
    double minLng = 180.0;
    double maxLng = -180.0;

    for (final sector in _sectors) {
      final points = sector['points'] as List<LatLng>;
      for (final point in points) {
        minLat = point.latitude < minLat ? point.latitude : minLat;
        maxLat = point.latitude > maxLat ? point.latitude : maxLat;
        minLng = point.longitude < minLng ? point.longitude : minLng;
        maxLng = point.longitude > maxLng ? point.longitude : maxLng;
      }
    }

    // Calculer le centre (sans padding car on ne change pas le zoom)
    final centerLat = (minLat + maxLat) / 2;
    final centerLng = (minLng + maxLng) / 2;

    // Lire le zoom actuel de la caméra pour le conserver exactement
    final currentZoom = _mapController.camera.zoom;

    // Centrer la carte sur ces limites SANS changer le zoom
    _mapController.move(LatLng(centerLat, centerLng), currentZoom);

    // Mettre à jour uniquement la position (pas le zoom)
    setState(() {
      _currentPosition = LatLng(centerLat, centerLng);
    });

    debugPrint('Carte centrée sur tous les secteurs (zoom conservé: $currentZoom)');
  }

  // Mettre à jour les items de la combobox de secteurs (avec setState)
  void _updateSectorItems() {
    // Créer l'item "Tous les secteurs"
    final List<DropdownMenuItem<int?>> items = [
      const DropdownMenuItem<int?>(
        value: null,
        child: Text('Tous les secteurs'),
      ),
    ];

    // Ajouter tous les secteurs
    for (final sector in _sectors) {
      items.add(
        DropdownMenuItem<int?>(
          value: sector['id'] as int,
          child: Text(sector['name'] as String),
        ),
      );
    }

    setState(() {
      _sectorItems = items;
    });
  }

  // Mettre à jour les items de la combobox de types de passage
  void _updatePassageTypeItems() {
    // Créer la liste des items
    final List<DropdownMenuItem<int?>> items = [
      const DropdownMenuItem<int?>(
        value: null,
        child: Text('Aucun passage'),
      ),
      const DropdownMenuItem<int?>(
        value: -1,
        child: Text('Tous les passages'),
      ),
    ];

    // Ajouter tous les types de passage depuis AppKeys
    for (final entry in AppKeys.typesPassages.entries) {
      final typeId = entry.key;
      final typeInfo = entry.value;
      final typeName = typeInfo['titres'] as String? ?? typeInfo['titre'] as String;

      items.add(
        DropdownMenuItem<int?>(
          value: typeId,
          child: Text(typeName),
        ),
      );
    }

    setState(() {
      _passageTypeItems = items;
    });
  }

  // Centrer la carte sur un secteur spécifique (sans changer le zoom)
  void _centerMapOnSpecificSector(int sectorId) {
    final sectorIndex = _sectors.indexWhere((s) => s['id'] == sectorId);
    if (sectorIndex == -1) return;

    // Mettre à jour le secteur sélectionné
    _selectedSectorId = sectorId;

    final sector = _sectors[sectorIndex];
    final points = sector['points'] as List<LatLng>;
    final sectorName = sector['name'] as String;

    debugPrint(
        'Centrage sur le secteur: $sectorName (ID: $sectorId) avec ${points.length} points');

    if (points.isEmpty) {
      debugPrint('Aucun point dans ce secteur!');
      return;
    }

    // Trouver les limites du secteur
    double minLat = 90.0;
    double maxLat = -90.0;
    double minLng = 180.0;
    double maxLng = -180.0;

    for (final point in points) {
      minLat = point.latitude < minLat ? point.latitude : minLat;
      maxLat = point.latitude > maxLat ? point.latitude : maxLat;
      minLng = point.longitude < minLng ? point.longitude : minLng;
      maxLng = point.longitude > maxLng ? point.longitude : maxLng;
    }

    // Vérifier si les coordonnées sont valides
    if (minLat >= maxLat || minLng >= maxLng) {
      debugPrint('Coordonnées invalides pour le secteur $sectorName');
      return;
    }

    // Calculer le centre (sans padding car on ne change pas le zoom)
    final centerLat = (minLat + maxLat) / 2;
    final centerLng = (minLng + maxLng) / 2;

    // CAPTURER le zoom actuel AVANT toute opération pour le conserver
    final preservedZoom = _currentZoom;

    // ACTIVER le flag pour bloquer la sauvegarde du zoom
    _isCenteringOnSector = true;

    // Centrer la carte sur le secteur en FORCANT le zoom actuel
    debugPrint('🔍 MapPage: Centrage sur secteur (zoom FORCÉ à conserver: $preservedZoom)');
    _mapController.move(LatLng(centerLat, centerLng), preservedZoom);

    // Mettre à jour UNIQUEMENT la position, PAS le zoom
    setState(() {
      _currentPosition = LatLng(centerLat, centerLng);
      // On ne touche PAS à _currentZoom !
    });

    // Sauvegarder la nouvelle position (le zoom ne sera pas sauvegardé grâce au flag)
    _saveSettings();

    // DÉSACTIVER le flag après un court délai pour permettre les sauvegardes normales
    Future.delayed(const Duration(milliseconds: 100), () {
      _isCenteringOnSector = false;
    });

    // Recharger les passages pour appliquer le filtre par secteur
    _loadPassages();
  }

  // Obtenir la position actuelle de l'utilisateur
  Future<void> _getUserLocation() async {
    try {
      // Afficher un indicateur de chargement
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('Recherche de votre position...'),
          duration: Duration(seconds: 2),
        ),
      );

      // Obtenir la position actuelle via le service de géolocalisation
      final position = await LocationService.getCurrentPosition();

      if (position != null) {
        // Mettre à jour la position sur la carte (utilise le zoom actuel, pas de zoom forcé)
        _updateMapPosition(position);

        // Sauvegarder la nouvelle position (le zoom est sauvegardé dans _updateMapPosition)
        _settingsBox.put('mapLat', position.latitude);
        _settingsBox.put('mapLng', position.longitude);

        // Informer l'utilisateur
        if (mounted) {
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(
              content: Text('Position actualisée'),
              backgroundColor: Colors.green,
              duration: Duration(seconds: 1),
            ),
          );
        }
      } else {
        // Informer l'utilisateur en cas d'échec
        if (mounted) {
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(
              content: Text(
                  'Impossible d\'obtenir votre position. Vérifiez vos paramètres de localisation.'),
              backgroundColor: Colors.red,
            ),
          );
        }
      }
    } catch (e) {
      // Gérer les erreurs
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text('Erreur: $e'),
            backgroundColor: Colors.red,
          ),
        );
      }
    }
  }

  // Méthode pour mettre à jour la position sur la carte
  void _updateMapPosition(LatLng position, {double? zoom}) {
    _mapController.move(
      position,
      zoom ?? _mapController.camera.zoom,
    );

    // Mettre à jour les variables d'état
    setState(() {
      _currentPosition = position;
      if (zoom != null) {
        _currentZoom = zoom;
      }
    });

    // Sauvegarder les paramètres après mise à jour de la position
    _saveSettings();
  }

  // Calculer le centre d'un polygone
  LatLng _calculatePolygonCenter(List<LatLng> points) {
    double sumLat = 0;
    double sumLng = 0;

    for (final point in points) {
      sumLat += point.latitude;
      sumLng += point.longitude;
    }

    return LatLng(sumLat / points.length, sumLng / points.length);
  }

  // Compter les passages par secteur (TOUS les passages, pas de filtre par sélection)
  Map<int, int> _countPassagesBySector() {
    final Map<int, int> passageCount = {};

    // Initialiser tous les secteurs à 0
    for (final sector in _sectors) {
      passageCount[sector['id'] as int] = 0;
    }

    // Compter TOUS les passages de tous les secteurs (ignorer la sélection)
    try {
      final passagesBox = Hive.box<PassageModel>(AppKeys.passagesBoxName);

      // Pour les users, récupérer leurs secteurs assignés
      Set<int>? userSectorIds;
      if (!isAdmin) {
        final userSectorBox = Hive.box<UserSectorModel>(AppKeys.userSectorBoxName);
        final currentOpeUserId = CurrentUserService.instance.opeUserId;
        if (currentOpeUserId != null) {
          userSectorIds = userSectorBox.values
              .where((us) => us.opeUserId == currentOpeUserId)
              .map((us) => us.fkSector)
              .toSet();
        }
      }

      for (var i = 0; i < passagesBox.length; i++) {
        final passage = passagesBox.getAt(i);
        if (passage != null && passage.fkSector != null) {
          // Pour les users, filtrer par leurs secteurs assignés
          if (!isAdmin && userSectorIds != null && !userSectorIds.contains(passage.fkSector)) {
            continue;
          }

          passageCount[passage.fkSector!] =
              (passageCount[passage.fkSector!] ?? 0) + 1;
        }
      }
    } catch (e) {
      debugPrint('Erreur lors du comptage des passages: $e');
    }

    return passageCount;
  }

  // Compter les membres par secteur
  Map<int, int> _countMembersBySector() {
    final Map<int, int> memberCount = {};

    // Initialiser tous les secteurs à 0
    for (final sector in _sectors) {
      memberCount[sector['id'] as int] = 0;
    }

    // Compter les membres depuis la box UserSector
    try {
      if (Hive.isBoxOpen(AppKeys.userSectorBoxName)) {
        final userSectorBox =
            Hive.box<UserSectorModel>(AppKeys.userSectorBoxName);
        for (var i = 0; i < userSectorBox.length; i++) {
          final userSector = userSectorBox.getAt(i);
          if (userSector != null) {
            memberCount[userSector.fkSector] =
                (memberCount[userSector.fkSector] ?? 0) + 1;
          }
        }
      }
    } catch (e) {
      debugPrint('Erreur lors du comptage des membres: $e');
    }

    return memberCount;
  }

  // Construire les marqueurs de labels pour les secteurs
  List<Marker> _buildSectorLabels() {
    debugPrint('🔄 _buildSectorLabels() appelé - ${_sectors.length} secteurs');
    // Ne pas afficher les labels en mode dessin ou suppression
    if (_sectors.isEmpty || _mapMode != MapMode.view) {
      return [];
    }

    // Utiliser les comptages stockés en mémoire (pas de recalcul)
    return _sectors.map((sector) {
      final points = sector['points'] as List<LatLng>;
      final center = _calculatePolygonCenter(points);
      final sectorId = sector['id'] as int;
      final sectorName = sector['name'] as String;
      final sectorColor = sector['color'] as Color;
      final count = _sectorPassageCount[sectorId] ?? 0;
      final members = _sectorMemberCount[sectorId] ?? 0;

      // Utiliser une couleur plus foncée pour le texte
      final textColor = _darkenColor(sectorColor, 0.4);

      return Marker(
        point: center,
        width: 200,
        height: 75,
        child: IgnorePointer(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                sectorName,
                style: TextStyle(
                  color: textColor,
                  fontWeight: FontWeight.bold,
                  fontSize: 14,
                  shadows: [
                    Shadow(
                      color: Colors.white.withOpacity(0.95),
                      offset: const Offset(0, 0),
                      blurRadius: 6,
                    ),
                  ],
                ),
                textAlign: TextAlign.center,
                overflow: TextOverflow.ellipsis,
              ),
              const SizedBox(height: 2),
              Text(
                '$count passage${count > 1 ? 's' : ''}',
                style: TextStyle(
                  color: textColor,
                  fontSize: 12,
                  fontWeight: FontWeight.w600,
                  shadows: [
                    Shadow(
                      color: Colors.white.withOpacity(0.95),
                      offset: const Offset(0, 0),
                      blurRadius: 5,
                    ),
                  ],
                ),
                textAlign: TextAlign.center,
              ),
              Text(
                '$members membre${members > 1 ? 's' : ''}',
                style: TextStyle(
                  color: textColor,
                  fontSize: 11,
                  fontWeight: FontWeight.w500,
                  shadows: [
                    Shadow(
                      color: Colors.white.withOpacity(0.95),
                      offset: const Offset(0, 0),
                      blurRadius: 5,
                    ),
                  ],
                ),
                textAlign: TextAlign.center,
              ),
            ],
          ),
        ),
      );
    }).toList();
  }

  // Méthode pour construire les marqueurs des passages
  /// Groupe les passages par adresse (pour fkHabitat=2)
  /// Clé: numero+rueBis+rue+ville
  Map<String, List<Map<String, dynamic>>> _groupPassagesByAddress() {
    final Map<String, List<Map<String, dynamic>>> grouped = {};

    for (final passage in _passages) {
      final PassageModel model = passage['model'] as PassageModel;

      // Ne grouper que les passages avec fkHabitat=2
      if (model.fkHabitat == 2) {
        final key = '${model.numero}|${model.rueBis}|${model.rue}|${model.ville}';
        grouped.putIfAbsent(key, () => []);
        grouped[key]!.add(passage);
      }
    }

    return grouped;
  }

  List<Marker> _buildMarkers() {
    debugPrint('🔄 _buildMarkers() appelé - ${_passages.length} passages');
    if (_passages.isEmpty) {
      return [];
    }

    final List<Marker> markers = [];

    // 1. Grouper les passages fkHabitat=2 par adresse
    final groupedPassages = _groupPassagesByAddress();
    final Set<int> groupedPassageIds = {};

    // Collecter les IDs des passages groupés
    for (final group in groupedPassages.values) {
      for (final passage in group) {
        final PassageModel model = passage['model'] as PassageModel;
        groupedPassageIds.add(model.id);
      }
    }

    // 2. Créer les markers pour passages individuels (fkHabitat=1 ou non groupés)
    for (final passage in _passages) {
      final PassageModel passageModel = passage['model'] as PassageModel;

      // Ignorer les passages déjà groupés
      if (groupedPassageIds.contains(passageModel.id)) {
        continue;
      }

      final int passageType = passage['type'] as int;
      final Color color1 = passage['color'] as Color;
      final bool hasNoSector = passageModel.fkSector == null;

      // Récupérer la couleur2 du type de passage
      Color color2 = Colors.white;
      if (AppKeys.typesPassages.containsKey(passageType)) {
        final colorValue =
            AppKeys.typesPassages[passageType]!['couleur2'] as int;
        color2 = Color(colorValue);
      }

      // Si le passage n'a pas de secteur, on met une bordure rouge épaisse
      final Color borderColor = hasNoSector ? Colors.red : color2;
      final double borderWidth = hasNoSector ? 3.0 : 1.0;

      markers.add(
        Marker(
          point: passage['position'] as LatLng,
          width: hasNoSector ? 18.0 : 14.0,
          height: hasNoSector ? 18.0 : 14.0,
          child: GestureDetector(
            onTap: () {
              _showPassageInfo(passage);
            },
            child: Container(
              decoration: BoxDecoration(
                color: color1,
                shape: BoxShape.circle,
                border: Border.all(
                  color: borderColor,
                  width: borderWidth,
                ),
              ),
            ),
          ),
        ),
      );
    }

    // 3. Créer les markers groupés (carrés avec dégradé blanc→vert selon avancement)
    for (final entry in groupedPassages.entries) {
      final passages = entry.value;
      if (passages.isEmpty) continue;

      // Utiliser la position du premier passage du groupe
      final position = passages.first['position'] as LatLng;
      final count = passages.length;
      final displayCount = count >= 99 ? '99' : count.toString();

      // Calculer le pourcentage de passages réalisés (fkType != 2)
      final models = passages.map((p) => p['model'] as PassageModel).toList();
      final realizedCount = models.where((p) => p.fkType != 2).length;
      final percentage = realizedCount / models.length;

      // Déterminer la couleur de remplissage selon le palier (5 niveaux)
      Color fillColor;
      if (percentage == 0) {
        // 0% : Blanc pur
        fillColor = Colors.white;
      } else if (percentage <= 0.25) {
        // 1-25% : Blanc cassé → Vert très clair
        fillColor = Color.lerp(Colors.white, const Color(0xFFB3F5E0), (percentage / 0.25))!;
      } else if (percentage <= 0.50) {
        // 26-50% : Vert très clair → Vert clair
        fillColor = Color.lerp(const Color(0xFFB3F5E0), const Color(0xFF66EBBB), ((percentage - 0.25) / 0.25))!;
      } else if (percentage <= 0.75) {
        // 51-75% : Vert clair → Vert moyen
        fillColor = Color.lerp(const Color(0xFF66EBBB), const Color(0xFF33E1A0), ((percentage - 0.50) / 0.25))!;
      } else if (percentage < 1.0) {
        // 76-99% : Vert moyen → Vert foncé
        fillColor = Color.lerp(const Color(0xFF33E1A0), const Color(0xFF00E09D), ((percentage - 0.75) / 0.25))!;
      } else {
        // 100% : Vert foncé (couleur "Effectué")
        fillColor = const Color(0xFF00E09D);
      }

      markers.add(
        Marker(
          point: position,
          width: 24.0,
          height: 24.0,
          child: GestureDetector(
            onTap: () {
              _showGroupedPassagesDialog(passages.first['model'] as PassageModel);
            },
            child: Container(
              decoration: BoxDecoration(
                color: fillColor,
                shape: BoxShape.rectangle,
                borderRadius: BorderRadius.circular(4),
                border: Border.all(
                  color: Colors.blue, // Bordure bleue toujours
                  width: 2,
                ),
              ),
              child: Center(
                child: Text(
                  displayCount,
                  style: TextStyle(
                    color: percentage < 0.5 ? Colors.black87 : Colors.white, // Texte noir sur fond clair, blanc sur fond foncé
                    fontSize: 12,
                    fontWeight: FontWeight.bold,
                  ),
                ),
              ),
            ),
          ),
        ),
      );
    }

    return markers;
  }

  // Méthode pour construire les polygones des secteurs
  List<Polygon> _buildPolygons() {
    debugPrint('🔄 _buildPolygons() appelé - ${_sectors.length} secteurs');
    if (_sectors.isEmpty) {
      return [];
    }

    return _sectors.map((sector) {
      final int sectorId = sector['id'] as int;
      final bool isSelected = _selectedSectorId == sectorId;
      final bool isMarkedForDeletion =
          _mapMode == MapMode.deleting && _sectorToDeleteId == sectorId;
      final bool isHovered =
          _mapMode == MapMode.deleting && _hoveredSectorId == sectorId;
      final bool isHoveredForEdit = _mapMode == MapMode.editing &&
          _hoveredSectorIdForEdit == sectorId &&
          _selectedSectorForEdit == null;
      final bool isSelectedForEdit =
          _mapMode == MapMode.editing && _selectedSectorForEdit?.id == sectorId;
      final Color sectorColor = sector['color'] as Color;

      // Déterminer la couleur et l'opacité selon l'état
      Color fillColor;
      Color borderColor;
      double borderWidth;

      if (isMarkedForDeletion) {
        // Secteur marqué pour suppression
        fillColor = Colors.red.withOpacity(0.5);
        borderColor = Colors.red;
        borderWidth = 4.0;
      } else if (isHovered) {
        // Secteur survolé en mode suppression
        fillColor = sectorColor.withOpacity(0.45);
        borderColor = Colors.red.withOpacity(0.8);
        borderWidth = 3.0;
      } else if (isHoveredForEdit) {
        // Secteur survolé en mode édition
        fillColor = sectorColor.withOpacity(0.45);
        borderColor = Colors.green;
        borderWidth = 4.0;
      } else if (isSelectedForEdit) {
        // Secteur sélectionné pour édition
        fillColor = sectorColor.withOpacity(0.5);
        borderColor = Colors.orange;
        borderWidth = 4.0;
      } else if (isSelected) {
        // Secteur sélectionné
        fillColor = sectorColor.withOpacity(0.5);
        borderColor = sectorColor;
        borderWidth = 3.0;
      } else {
        // Secteur normal
        fillColor = sectorColor.withOpacity(0.3);
        borderColor = sectorColor.withOpacity(0.8);
        borderWidth = 2.0;
      }

      return Polygon(
        points: sector['points'] as List<LatLng>,
        color: fillColor,
        borderColor: borderColor,
        borderStrokeWidth: borderWidth,
      );
    }).toList();
  }

  // Afficher les informations d'un passage lorsqu'on clique dessus
  void _showPassageInfo(Map<String, dynamic> passage) {
    final PassageModel passageModel = passage['model'] as PassageModel;

    showDialog(
      context: context,
      builder: (context) => PassageMapDialog(
        passage: passageModel,
        isAdmin: true,
        onDeleted: () {
          // Recharger les passages après suppression
          _loadPassages();
        },
      ),
    );
  }

  // Afficher le dialogue des passages groupés (immeuble)
  void _showGroupedPassagesDialog(PassageModel referencePassage) {
    showDialog(
      context: context,
      builder: (context) => GroupedPassagesDialog(
        referencePassage: referencePassage,
        isAdmin: isAdmin,
      ),
    );
  }

  // Démarrer le mode dessin
  void _startDrawingMode() {
    if (!canEditSectors) return; // Vérifier les permissions
    setState(() {
      _mapMode = MapMode.drawing;
      _drawingPoints.clear();

      // Sélectionner automatiquement "Aucun passage"
      _selectedPassageTypeFilter = null;
      _settingsBox.put('selectedPassageTypeFilter', null);
    });

    // Recharger les passages avec le nouveau filtre
    _loadPassages();
  }

  // Démarrer le mode suppression
  void _startDeletingMode() {
    if (!canEditSectors) return; // Vérifier les permissions
    setState(() {
      _mapMode = MapMode.deleting;
      _sectorToDeleteId = null;

      // Sélectionner automatiquement "Aucun passage"
      _selectedPassageTypeFilter = null;
      _settingsBox.put('selectedPassageTypeFilter', null);
    });

    // Recharger les passages avec le nouveau filtre
    _loadPassages();
  }

  // Démarrer le mode édition
  void _startEditingMode() {
    if (!canEditSectors) return; // Vérifier les permissions
    setState(() {
      _mapMode = MapMode.editing;
      _selectedSectorForEdit = null;
      _editingPoints.clear();

      // Sélectionner automatiquement "Aucun passage"
      _selectedPassageTypeFilter = null;
      _settingsBox.put('selectedPassageTypeFilter', null);
    });

    // Recharger les passages avec le nouveau filtre
    _loadPassages();
  }

  // Construire la carte d'aide pour le mode création
  Widget _buildHelpCard() {
    return Material(
      elevation: 4,
      borderRadius: BorderRadius.circular(12),
      child: Container(
        padding: const EdgeInsets.all(16),
        width: 320,
        decoration: BoxDecoration(
          color: Colors.white.withOpacity(0.95),
          borderRadius: BorderRadius.circular(12),
          border: Border.all(
            color: Colors.blue.withOpacity(0.3),
            width: 1,
          ),
        ),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              children: [
                Icon(
                  Icons.info_outline,
                  color: Colors.blue,
                  size: 24,
                ),
                const SizedBox(width: 8),
                Text(
                  'Création d\'un secteur',
                  style: TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.bold,
                    color: Colors.blue[800],
                  ),
                ),
              ],
            ),
            const SizedBox(height: 12),
            Text(
              'Cliquer sur la carte pour créer le 1er point de contour du nouveau secteur. Ensuite créer autant de points nécessaires pour dessiner les contours du secteur, jusqu\'à cliquer une dernière fois sur le 1er point pour finaliser la création du secteur.',
              style: TextStyle(
                fontSize: 14,
                color: Colors.grey[700],
                height: 1.4,
              ),
            ),
            const SizedBox(height: 8),
            Text(
              '• Clic droit ou Ctrl+clic sur un point pour le supprimer',
              style: TextStyle(
                fontSize: 13,
                color: Colors.grey[600],
                fontStyle: FontStyle.italic,
              ),
            ),
            const SizedBox(height: 4),
            Text(
              '• Cliquer-glisser sur un point pour le déplacer',
              style: TextStyle(
                fontSize: 13,
                color: Colors.grey[600],
                fontStyle: FontStyle.italic,
              ),
            ),
            const SizedBox(height: 4),
            Text(
              '• Bouton "Annuler dernier" pour supprimer le dernier point ajouté',
              style: TextStyle(
                fontSize: 13,
                color: Colors.grey[600],
                fontStyle: FontStyle.italic,
              ),
            ),
            const SizedBox(height: 12),
            Row(
              children: [
                Container(
                  width: 20,
                  height: 20,
                  decoration: BoxDecoration(
                    color: Colors.green,
                    shape: BoxShape.circle,
                    border: Border.all(
                      color: Colors.white,
                      width: 2,
                    ),
                  ),
                  child: const Center(
                    child: Text(
                      '1',
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 10,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                ),
                const SizedBox(width: 8),
                Text(
                  'Premier point',
                  style: TextStyle(
                    fontSize: 12,
                    color: Colors.grey[600],
                  ),
                ),
                const SizedBox(width: 16),
                Container(
                  width: 16,
                  height: 16,
                  decoration: BoxDecoration(
                    color: Colors.blue,
                    shape: BoxShape.circle,
                    border: Border.all(
                      color: Colors.white,
                      width: 2,
                    ),
                  ),
                ),
                const SizedBox(width: 8),
                Text(
                  'Points suivants',
                  style: TextStyle(
                    fontSize: 12,
                    color: Colors.grey[600],
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }

  // Construire la carte d'aide pour le mode suppression
  Widget _buildDeleteHelpCard() {
    return Material(
      elevation: 4,
      borderRadius: BorderRadius.circular(12),
      child: Container(
        padding: const EdgeInsets.all(16),
        width: 360,
        decoration: BoxDecoration(
          color: Colors.white.withOpacity(0.95),
          borderRadius: BorderRadius.circular(12),
          border: Border.all(
            color: Colors.red.withOpacity(0.3),
            width: 1,
          ),
        ),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              children: [
                Icon(
                  Icons.warning_amber_rounded,
                  color: Colors.red,
                  size: 24,
                ),
                const SizedBox(width: 8),
                Text(
                  'Suppression d\'un secteur',
                  style: TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.bold,
                    color: Colors.red[800],
                  ),
                ),
              ],
            ),
            const SizedBox(height: 12),
            Text(
              'Vous devez sélectionner le secteur que vous voulez supprimer en cliquant dessus une seule fois. Tous les passages à finaliser et sans infos d\'habitant seront supprimés. Les autres passages seront gardés, mais sans secteur, en attendant que vous recréez un nouveau secteur sur ces passages.',
              style: TextStyle(
                fontSize: 14,
                color: Colors.grey[700],
                height: 1.4,
              ),
            ),
            const SizedBox(height: 16),
            ElevatedButton.icon(
              onPressed: () {
                setState(() {
                  _mapMode = MapMode.view;
                  _sectorToDeleteId = null;
                });
              },
              icon: const Icon(Icons.cancel, size: 18),
              label: const Text('Annuler'),
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.grey,
                foregroundColor: Colors.white,
                minimumSize: const Size(100, 36),
              ),
            ),
          ],
        ),
      ),
    );
  }

  // Construire la carte d'aide pour le mode édition
  Widget _buildEditHelpCard() {
    return Material(
      elevation: 4,
      borderRadius: BorderRadius.circular(12),
      child: Container(
        padding: const EdgeInsets.all(16),
        width: 340,
        decoration: BoxDecoration(
          color: Colors.white.withOpacity(0.95),
          borderRadius: BorderRadius.circular(12),
          border: Border.all(
            color: Colors.orange.withOpacity(0.3),
            width: 1,
          ),
        ),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              children: [
                Icon(
                  Icons.edit_location_alt,
                  color: Colors.orange,
                  size: 24,
                ),
                const SizedBox(width: 8),
                Text(
                  'Modification d\'un secteur',
                  style: TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.bold,
                    color: Colors.orange[800],
                  ),
                ),
              ],
            ),
            const SizedBox(height: 12),
            if (_selectedSectorForEdit == null) ...[
              Text(
                'Cliquez sur le secteur que vous souhaitez modifier.',
                style: TextStyle(
                  fontSize: 14,
                  color: Colors.grey[700],
                  height: 1.4,
                ),
              ),
            ] else ...[
              Text(
                'Secteur sélectionné : ${_selectedSectorForEdit!.libelle}',
                style: TextStyle(
                  fontSize: 14,
                  fontWeight: FontWeight.bold,
                  color: Colors.orange[800],
                ),
              ),
              const SizedBox(height: 8),
              Container(
                padding: const EdgeInsets.all(8),
                decoration: BoxDecoration(
                  color: Colors.orange.withOpacity(0.1),
                  borderRadius: BorderRadius.circular(4),
                  border:
                      Border.all(color: Colors.orange.withOpacity(0.3)),
                ),
                child: Text(
                  'La modification est verrouillée sur ce secteur.\n'
                  'Enregistrez ou annulez avant de modifier un autre secteur.',
                  style: TextStyle(
                    fontSize: 12,
                    color: Colors.orange[700],
                    fontWeight: FontWeight.w500,
                  ),
                ),
              ),
              const SizedBox(height: 8),
              Text(
                '• Cliquer-glisser sur un point pour le déplacer\n'
                '• Clic droit ou Ctrl+clic sur un point pour le supprimer\n'
                '• Cliquer sur les points intermédiaires pour en ajouter',
                style: TextStyle(
                  fontSize: 13,
                  color: Colors.grey[600],
                  fontStyle: FontStyle.italic,
                ),
              ),
            ],
          ],
        ),
      ),
    );
  }

  // Annuler le mode dessin
  void _cancelDrawingMode() {
    setState(() {
      _mapMode = MapMode.view;
      _drawingPoints.clear();
    });
  }

  // Annuler le mode édition
  void _cancelEditingMode() {
    setState(() {
      _mapMode = MapMode.view;
      _selectedSectorForEdit = null;
      _editingPoints.clear();
      _originalPoints.clear();
    });
  }

  // Sauvegarder le secteur modifié
  Future<void> _saveEditedSector() async {
    if (_selectedSectorForEdit == null || _editingPoints.isEmpty) return;

    // Vérifier que le polygone est valide
    if (!_isValidPolygon(_editingPoints)) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text(
              'Le secteur contient des lignes qui se croisent. Veuillez corriger le tracé.'),
          backgroundColor: Colors.red,
          duration: Duration(seconds: 3),
        ),
      );
      return;
    }

    // Appliquer la correction automatique des points adjacents (comme pour la création)
    // En excluant le secteur actuel de la vérification
    final correctedPoints = _correctPointsForAdjacency(_editingPoints,
        excludeSectorId: _selectedSectorForEdit!.id);

    // Vérifier si des points ont été corrigés
    bool pointsWereCorrected = false;
    for (int i = 0; i < _editingPoints.length; i++) {
      if (_editingPoints[i] != correctedPoints[i]) {
        pointsWereCorrected = true;
        break;
      }
    }

    // Mettre à jour les points avec la version corrigée
    setState(() {
      _editingPoints = correctedPoints;
    });

    // Informer l'utilisateur si des corrections ont été appliquées
    if (pointsWereCorrected) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text(
              'Les points ont été ajustés automatiquement pour éviter les chevauchements'),
          backgroundColor: Colors.blue,
          duration: Duration(seconds: 2),
        ),
      );
    }

    // Vérifier les chevauchements avec les autres secteurs (avec les points corrigés)
    bool hasOverlap = false;
    String? overlappingSectorName;

    for (final sector in _sectors) {
      // Ne pas vérifier avec lui-même
      if (sector['id'] == _selectedSectorForEdit!.id) continue;

      final sectorPoints = sector['points'] as List<LatLng>;
      if (_doPolygonsOverlap(correctedPoints, sectorPoints)) {
        hasOverlap = true;
        overlappingSectorName = sector['name'] as String;
        break;
      }
    }

    if (hasOverlap) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text(
              'Le secteur modifié chevauche avec le secteur "$overlappingSectorName"'),
          backgroundColor: Colors.red,
          duration: const Duration(seconds: 3),
        ),
      );
      return;
    }

    // Préparer les coordonnées pour le dialog (avec les points corrigés)
    final coordinates = correctedPoints
        .map((point) => [point.latitude, point.longitude])
        .toList();

    // Réinitialiser le mode AVANT d'afficher le dialog
    setState(() {
      _mapMode = MapMode.view;
      _editingPoints.clear();
      _originalPoints.clear();
    });

    // Afficher le dialog de modification (comme pour la création)
    await _showSectorDialog(
        existingSector: _selectedSectorForEdit, coordinates: coordinates);

    // Réinitialiser la sélection après le dialog
    setState(() {
      _selectedSectorForEdit = null;
    });
  }

  // Supprimer un point de dessin
  void _removeDrawingPoint(int index) {
    if (_drawingPoints.length <= 1) {
      // Ne pas permettre de supprimer le dernier point
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('Un secteur doit avoir au moins un point'),
          backgroundColor: Colors.orange,
          duration: Duration(seconds: 1),
        ),
      );
      return;
    }

    setState(() {
      _drawingPoints.removeAt(index);
      // Si on supprime le point sélectionné, désélectionner
      if (_draggingPointIndex == index) {
        _draggingPointIndex = null;
      } else if (_draggingPointIndex != null && _draggingPointIndex! > index) {
        // Ajuster l'index si nécessaire
        _draggingPointIndex = _draggingPointIndex! - 1;
      }
    });

    // Afficher un message de confirmation
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(
        content: Text('Point supprimé'),
        backgroundColor: Colors.green,
        duration: Duration(seconds: 1),
      ),
    );
  }

  // Déplacer un point de dessin

  // Annuler le dernier point ajouté
  void _undoLastPoint() {
    if (_drawingPoints.isEmpty) return;

    setState(() {
      _drawingPoints.removeLast();
      // Si on avait sélectionné le dernier point, désélectionner
      if (_draggingPointIndex != null &&
          _draggingPointIndex! >= _drawingPoints.length) {
        _draggingPointIndex = null;
      }
    });

    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(
        content: Text('Dernier point annulé'),
        backgroundColor: Colors.orange,
        duration: Duration(seconds: 1),
      ),
    );
  }

  // Gérer le tap sur la carte
  void _handleMapTap(LatLng position) {
    if (_mapMode == MapMode.drawing) {
      // Détecter le magnétisme
      final snapPoint = _detectSnapPoint(position);
      final finalPosition = snapPoint ?? position;

      // Si c'est le premier point ou un nouveau point
      if (_drawingPoints.isEmpty) {
        // Vérifier que le premier point n'est pas dans un secteur existant
        if (_isPointInsideExistingSector(finalPosition)) {
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(
              content: Text(
                  'Impossible de créer un point à l\'intérieur d\'un secteur existant'),
              backgroundColor: Colors.red,
              duration: Duration(seconds: 2),
            ),
          );
          return;
        }
        setState(() {
          _drawingPoints.add(finalPosition);
        });
      } else {
        // Vérifier si on clique sur le premier point pour fermer le polygone
        final firstPoint = _drawingPoints.first;
        final distance = _calculateDistance(position, firstPoint);

        // Si on clique proche du premier point (dans un rayon de 30 mètres)
        if (_drawingPoints.length >= 3 && distance < 30) {
          // Vérifier que le polygone est valide avant de finaliser
          if (_isValidPolygon(_drawingPoints)) {
            // Finaliser la création du secteur
            _finalizeSectorCreation();
          } else {
            ScaffoldMessenger.of(context).showSnackBar(
              const SnackBar(
                content: Text(
                    'Le secteur contient des lignes qui se croisent. Veuillez corriger le tracé.'),
                backgroundColor: Colors.red,
                duration: Duration(seconds: 3),
              ),
            );
          }
        } else {
          // Vérifier que l'ajout du nouveau point ne crée pas de croisement
          if (_drawingPoints.length >= 2) {
            // Vérifier s'il y a un croisement avec la nouvelle ligne
            final lastPoint = _drawingPoints.last;
            bool hasCrossing = false;

            // Vérifier avec toutes les lignes existantes sauf la dernière
            for (int i = 0; i < _drawingPoints.length - 2; i++) {
              if (_doSegmentsIntersect(lastPoint, finalPosition,
                  _drawingPoints[i], _drawingPoints[i + 1])) {
                hasCrossing = true;
                break;
              }
            }

            if (hasCrossing) {
              ScaffoldMessenger.of(context).showSnackBar(
                const SnackBar(
                  content: Text(
                      'Cette ligne croiserait une ligne existante du secteur'),
                  backgroundColor: Colors.orange,
                  duration: Duration(seconds: 2),
                ),
              );
              return;
            }
          }

          // Vérifier que le nouveau point n'est pas dans un secteur existant
          if (_isPointInsideExistingSector(finalPosition)) {
            ScaffoldMessenger.of(context).showSnackBar(
              const SnackBar(
                content: Text(
                    'Impossible de créer un point à l\'intérieur d\'un secteur existant'),
                backgroundColor: Colors.red,
                duration: Duration(seconds: 2),
              ),
            );
            return;
          }

          // Ajouter le nouveau point
          setState(() {
            _drawingPoints.add(finalPosition);
            // Réinitialiser le snap après l'ajout
            _snapPoint = null;
          });
        }
      }
    } else if (_mapMode == MapMode.deleting) {
      // En mode suppression, trouver le secteur cliqué
      _handleSectorClick(position);
    } else if (_mapMode == MapMode.editing) {
      // En mode édition, sélectionner le secteur à modifier seulement si aucun n'est déjà sélectionné
      if (_selectedSectorForEdit == null) {
        _handleSectorClickForEdit(position);
      } else {
        // Vérifier si on clique sur un autre secteur
        for (final sector in _sectors) {
          final points = sector['points'] as List<LatLng>;
          if (_isPointInPolygon(position, points) &&
              sector['id'] != _selectedSectorForEdit!.id) {
            // Afficher un message d'avertissement
            ScaffoldMessenger.of(context).showSnackBar(
              const SnackBar(
                content: Text(
                    'Veuillez enregistrer ou annuler les modifications en cours avant de sélectionner un autre secteur'),
                backgroundColor: Colors.orange,
                duration: Duration(seconds: 3),
              ),
            );
            break;
          }
        }
      }
    }
  }

  // Calculer la distance entre deux points (en mètres)
  double _calculateDistance(LatLng point1, LatLng point2) {
    final Distance distance = Distance();
    return distance.as(LengthUnit.Meter, point1, point2);
  }

  // Détecter le point d'accrochage le plus proche
  LatLng? _detectSnapPoint(LatLng currentPoint) {
    if (_sectors.isEmpty) return null;

    LatLng? bestSnapPoint;
    double bestDistance = _snapDistance;

    // Parcourir tous les secteurs
    for (final sector in _sectors) {
      final points = sector['points'] as List<LatLng>;
      final sectorId = sector['id'] as int;

      // En mode édition, ignorer le secteur en cours d'édition
      if (_mapMode == MapMode.editing &&
          _selectedSectorForEdit != null &&
          sectorId == _selectedSectorForEdit!.id) {
        continue;
      }

      // Vérifier la proximité avec chaque point du secteur
      for (int i = 0; i < points.length; i++) {
        final distance = _calculateDistance(currentPoint, points[i]);
        if (distance < bestDistance) {
          bestDistance = distance;
          bestSnapPoint = points[i];
        }
      }

      // Vérifier la proximité avec chaque segment du secteur
      for (int i = 0; i < points.length; i++) {
        final start = points[i];
        final end = points[(i + 1) % points.length];

        // Calculer le point le plus proche sur le segment
        final snapPoint = _getClosestPointOnSegment(currentPoint, start, end);
        final distance = _calculateDistance(currentPoint, snapPoint);

        if (distance < bestDistance) {
          bestDistance = distance;
          bestSnapPoint = snapPoint;
        }
      }
    }

    // Mettre à jour l'état du snap
    if (bestSnapPoint != null) {
      _snapPoint = bestSnapPoint;
    } else {
      _snapPoint = null;
    }

    return bestSnapPoint;
  }

  // Corriger les points pour éviter les chevauchements avec les secteurs adjacents
  List<LatLng> _correctPointsForAdjacency(List<LatLng> points,
      {int? excludeSectorId}) {
    final correctedPoints = List<LatLng>.from(points);
    const double snapDistance =
        10.0; // Distance pour détecter l'adjacence (10m)
    const double correctionOffset =
        1.0; // Décalage de correction réduit (1m vers l'intérieur)

    // Première passe : identifier les segments adjacents et corriger
    final Map<int, List<LatLng>> pointCorrections = {};

    // Pour chaque point, collecter toutes les corrections nécessaires
    for (int i = 0; i < correctedPoints.length; i++) {
      final point = correctedPoints[i];
      final List<LatLng> corrections = [];

      // Vérifier la proximité avec tous les secteurs existants
      for (final sector in _sectors) {
        // Exclure le secteur en cours d'édition si spécifié
        if (excludeSectorId != null && sector['id'] == excludeSectorId) {
          continue;
        }

        final sectorPoints = sector['points'] as List<LatLng>;

        // Vérifier la proximité avec les segments du secteur
        for (int j = 0; j < sectorPoints.length; j++) {
          final segStart = sectorPoints[j];
          final segEnd = sectorPoints[(j + 1) % sectorPoints.length];

          // Point le plus proche sur le segment
          final closestPoint =
              _getClosestPointOnSegment(point, segStart, segEnd);
          final distance = _calculateDistance(point, closestPoint);

          // Si le point est proche du segment
          if (distance < snapDistance && distance > 0.1) {
            // Ignorer si déjà sur le segment
            // Ne corriger que si vraiment nécessaire (très proche mais pas exactement sur le segment)
            if (distance < 2.0) {
              // Correction seulement si moins de 2m
              final offsetPoint = _offsetPointInward(
                  closestPoint, correctedPoints, i, correctionOffset);
              if (offsetPoint != null) {
                corrections.add(offsetPoint);
              }
            }
          }
        }

        // Vérifier la proximité avec les sommets du secteur
        for (final sectorPoint in sectorPoints) {
          final distance = _calculateDistance(point, sectorPoint);
          // Tolérer les sommets partagés (très courant pour les secteurs adjacents)
          if (distance < 1.0) {
            // Seulement si TRÈS proche (moins de 1m)
            // Pour les sommets partagés, ne pas corriger ou corriger très peu
            // car c'est normal d'avoir des sommets communs
            continue; // Ignorer les sommets parfaitement alignés
          }
        }
      }

      // Stocker toutes les corrections pour ce point
      if (corrections.isNotEmpty) {
        pointCorrections[i] = corrections;
      }
    }

    // Appliquer les corrections en moyennant si plusieurs corrections existent
    pointCorrections.forEach((index, corrections) {
      if (corrections.length == 1) {
        correctedPoints[index] = corrections.first;
      } else {
        // Si plusieurs corrections, utiliser la moyenne pondérée
        double avgLat = 0;
        double avgLng = 0;
        for (final correction in corrections) {
          avgLat += correction.latitude;
          avgLng += correction.longitude;
        }
        correctedPoints[index] = LatLng(
          avgLat / corrections.length,
          avgLng / corrections.length,
        );
      }
    });

    // Deuxième passe : s'assurer qu'il n'y a pas de chevauchement
    return _ensureNoIntersection(correctedPoints,
        excludeSectorId: excludeSectorId);
  }

  // Décaler un point vers l'intérieur du polygone
  LatLng? _offsetPointInward(
      LatLng point, List<LatLng> polygon, int pointIndex, double offsetMeters) {
    if (polygon.length < 3) return null;

    // Obtenir les points adjacents
    final prevIndex = (pointIndex - 1 + polygon.length) % polygon.length;
    final nextIndex = (pointIndex + 1) % polygon.length;
    final prevPoint = polygon[prevIndex];
    final nextPoint = polygon[nextIndex];

    // Calculer les vecteurs des segments adjacents
    final vec1 = LatLng(
      point.latitude - prevPoint.latitude,
      point.longitude - prevPoint.longitude,
    );
    final vec2 = LatLng(
      nextPoint.latitude - point.latitude,
      nextPoint.longitude - point.longitude,
    );

    // Calculer la normale (perpendiculaire) au segment pour le décalage
    // On utilise le produit vectoriel pour obtenir la direction perpendiculaire
    final crossProduct =
        vec1.latitude * vec2.longitude - vec1.longitude * vec2.latitude;

    // Déterminer la direction vers l'intérieur du polygone
    final sign = crossProduct > 0 ? 1.0 : -1.0;

    // Calculer la bissectrice normalisée
    final bisectorLat = -(vec1.latitude + vec2.latitude) * sign;
    final bisectorLng = -(vec1.longitude + vec2.longitude) * sign;

    final length =
        math.sqrt(bisectorLat * bisectorLat + bisectorLng * bisectorLng);
    if (length > 0) {
      // Convertir le décalage en degrés avec une meilleure approximation
      final latRad = point.latitude * math.pi / 180;
      final offsetDegreesLat = offsetMeters / 111320.0;
      final offsetDegreesLng = offsetMeters / (111320.0 * math.cos(latRad));

      return LatLng(
        point.latitude + (bisectorLat / length) * offsetDegreesLat,
        point.longitude + (bisectorLng / length) * offsetDegreesLng,
      );
    }

    return null;
  }

  // S'assurer qu'il n'y a pas d'intersection après correction
  List<LatLng> _ensureNoIntersection(List<LatLng> points,
      {int? excludeSectorId}) {
    List<LatLng> correctedPoints = List<LatLng>.from(points);
    const int maxIterations = 5; // Éviter les boucles infinies
    int iteration = 0;

    // Continuer à corriger jusqu'à ce qu'il n'y ait plus de chevauchement
    while (iteration < maxIterations) {
      bool hasOverlap = false;
      List<List<LatLng>> overlappingSectors = [];

      // Collecter tous les secteurs qui chevauchent
      for (final sector in _sectors) {
        // Exclure le secteur en cours d'édition si spécifié
        if (excludeSectorId != null && sector['id'] == excludeSectorId) {
          continue;
        }

        final sectorPoints = sector['points'] as List<LatLng>;

        if (_doPolygonsOverlap(correctedPoints, sectorPoints)) {
          hasOverlap = true;
          overlappingSectors.add(sectorPoints);
        }
      }

      // Si pas de chevauchement, on a terminé
      if (!hasOverlap) {
        break;
      }

      // Appliquer une correction pour tous les secteurs qui chevauchent
      correctedPoints =
          _applyMultiSectorCorrection(correctedPoints, overlappingSectors);
      iteration++;
    }

    return correctedPoints;
  }

  // Appliquer une correction pour plusieurs secteurs adjacents
  List<LatLng> _applyMultiSectorCorrection(
      List<LatLng> newPoints, List<List<LatLng>> overlappingSectors) {
    final corrected = List<LatLng>.from(newPoints);
    const double strongOffset = 3.0; // Décalage de base (3m)
    const double additionalOffset = 1.0; // Décalage supplémentaire par secteur

    // Pour chaque point du nouveau polygone
    for (int i = 0; i < corrected.length; i++) {
      final point = corrected[i];
      List<LatLng> corrections = [];

      // Calculer les corrections nécessaires pour chaque secteur chevauchant
      for (final sectorPoints in overlappingSectors) {
        // Vérifier si le point est proche ou à l'intérieur du secteur
        if (_isPointInPolygon(point, sectorPoints) ||
            _isPointOnPolygonBorder(point, sectorPoints, tolerance: 2.0)) {
          // Trouver le point le plus proche sur le contour
          LatLng? closestBoundaryPoint;
          double minDistance = double.infinity;

          for (int j = 0; j < sectorPoints.length; j++) {
            final start = sectorPoints[j];
            final end = sectorPoints[(j + 1) % sectorPoints.length];
            final closestPoint = _getClosestPointOnSegment(point, start, end);
            final distance = _calculateDistance(point, closestPoint);

            if (distance < minDistance) {
              minDistance = distance;
              closestBoundaryPoint = closestPoint;
            }
          }

          if (closestBoundaryPoint != null) {
            // Calculer la direction d'éloignement
            final direction = LatLng(
              point.latitude - closestBoundaryPoint.latitude,
              point.longitude - closestBoundaryPoint.longitude,
            );

            final length = math.sqrt(direction.latitude * direction.latitude +
                direction.longitude * direction.longitude);

            if (length > 0) {
              // Appliquer un décalage proportionnel au nombre de secteurs adjacents
              final totalOffset =
                  strongOffset + (additionalOffset * overlappingSectors.length);
              final offsetDegreesLat = totalOffset / 111320.0;
              final offsetDegreesLng = totalOffset /
                  (111320.0 * math.cos(point.latitude * math.pi / 180));

              corrections.add(LatLng(
                closestBoundaryPoint.latitude +
                    (direction.latitude / length) * offsetDegreesLat,
                closestBoundaryPoint.longitude +
                    (direction.longitude / length) * offsetDegreesLng,
              ));
            }
          }
        }
      }

      // Si des corrections ont été calculées, utiliser la moyenne
      if (corrections.isNotEmpty) {
        double avgLat = 0;
        double avgLng = 0;
        for (final correction in corrections) {
          avgLat += correction.latitude;
          avgLng += correction.longitude;
        }
        corrected[i] = LatLng(
          avgLat / corrections.length,
          avgLng / corrections.length,
        );
      }
    }

    return corrected;
  }

  // Appliquer le magnétisme automatique à tous les points d'un secteur
  List<LatLng> _applyAutomaticMagnetism(
      List<LatLng> points, int currentSectorId) {
    final magnetizedPoints = List<LatLng>.from(points);
    const double autoSnapDistance = 10.0; // Distance automatique de 10m

    // Pour chaque point du secteur
    for (int i = 0; i < magnetizedPoints.length; i++) {
      LatLng? bestSnapPoint;
      double bestDistance = autoSnapDistance;

      // Parcourir tous les autres secteurs
      for (final sector in _sectors) {
        final sectorId = sector['id'] as int;

        // Ignorer le secteur actuel
        if (sectorId == currentSectorId) continue;

        final sectorPoints = sector['points'] as List<LatLng>;

        // Vérifier la proximité avec chaque point du secteur adjacent
        for (final sectorPoint in sectorPoints) {
          final distance = _calculateDistance(magnetizedPoints[i], sectorPoint);
          if (distance < bestDistance) {
            bestDistance = distance;
            bestSnapPoint = sectorPoint;
          }
        }

        // Vérifier la proximité avec chaque segment du secteur adjacent
        for (int j = 0; j < sectorPoints.length; j++) {
          final start = sectorPoints[j];
          final end = sectorPoints[(j + 1) % sectorPoints.length];

          // Calculer le point le plus proche sur le segment
          final snapPoint =
              _getClosestPointOnSegment(magnetizedPoints[i], start, end);
          final distance = _calculateDistance(magnetizedPoints[i], snapPoint);

          if (distance < bestDistance) {
            bestDistance = distance;
            bestSnapPoint = snapPoint;
          }
        }
      }

      // Appliquer le magnétisme si un point proche a été trouvé
      if (bestSnapPoint != null) {
        magnetizedPoints[i] = bestSnapPoint;
      }
    }

    return magnetizedPoints;
  }

  // Calculer le point le plus proche sur un segment
  LatLng _getClosestPointOnSegment(
      LatLng point, LatLng segStart, LatLng segEnd) {
    final dx = segEnd.longitude - segStart.longitude;
    final dy = segEnd.latitude - segStart.latitude;

    if (dx == 0 && dy == 0) {
      return segStart; // Le segment est un point
    }

    // Calculer la projection du point sur la ligne définie par le segment
    final t = ((point.longitude - segStart.longitude) * dx +
            (point.latitude - segStart.latitude) * dy) /
        (dx * dx + dy * dy);

    // Limiter t entre 0 et 1 pour rester sur le segment
    final tClamped = t.clamp(0.0, 1.0);

    // Calculer le point projeté
    return LatLng(
      segStart.latitude + tClamped * dy,
      segStart.longitude + tClamped * dx,
    );
  }

  // Gérer le survol de la souris en mode dessin
  void _handleDrawingHover(PointerHoverEvent event) {
    // Récupérer la taille du widget
    final RenderBox? renderBox = context.findRenderObject() as RenderBox?;
    if (renderBox == null) return;

    // Convertir la position en coordonnées géographiques
    final localPosition = renderBox.globalToLocal(event.position);
    final mapSize = renderBox.size;
    final camera = _mapController.camera;

    // Calculer le décalage par rapport au centre
    final dx = localPosition.dx - (mapSize.width / 2);
    final dy = localPosition.dy - (mapSize.height / 2);

    // Utiliser la projection Web Mercator
    const double tileSize = 256.0;
    final scale = math.pow(2, camera.zoom);

    final centerX = (camera.center.longitude + 180) / 360 * tileSize * scale;
    final centerLatRad = camera.center.latitude * math.pi / 180;
    final centerY = (1 -
            math.log(math.tan(centerLatRad) + 1 / math.cos(centerLatRad)) /
                math.pi) /
        2 *
        tileSize *
        scale;

    final mouseX = centerX + dx;
    final mouseY = centerY + dy;

    final lng = mouseX / (tileSize * scale) * 360 - 180;
    final n = math.pi - 2 * math.pi * mouseY / (tileSize * scale);
    final lat = 180 / math.pi * math.atan(0.5 * (math.exp(n) - math.exp(-n)));

    final mousePosition = LatLng(lat, lng);

    // Détecter le magnétisme
    final snapPoint = _detectSnapPoint(mousePosition);

    // Mettre à jour l'affichage du point d'accrochage
    if (snapPoint != _snapPoint) {
      setState(() {
        _snapPoint = snapPoint;
      });
    }
  }

  // Gérer le survol de la souris en mode édition
  void _handleEditingHover(PointerHoverEvent event) {
    // Même logique que pour le mode dessin
    _handleDrawingHover(event);
  }

  // Gérer le survol de la souris en mode suppression et édition
  void _handleMouseHover(PointerHoverEvent event) {
    if (_mapMode != MapMode.deleting && _mapMode != MapMode.editing) {
      // Réinitialiser le survol si on n'est pas en mode suppression ou édition
      if (_hoveredSectorId != null) {
        setState(() {
          _hoveredSectorId = null;
        });
      }
      if (_hoveredSectorIdForEdit != null) {
        setState(() {
          _hoveredSectorIdForEdit = null;
        });
      }
      return;
    }

    // Récupérer la taille du widget MapboxMap
    final RenderBox? renderBox = context.findRenderObject() as RenderBox?;
    if (renderBox == null) return;

    // Convertir la position globale en position locale relative au widget
    final localPosition = renderBox.globalToLocal(event.position);

    // Utiliser une méthode plus précise basée sur la projection Web Mercator
    final mapSize = renderBox.size;
    final camera = _mapController.camera;

    // Calculer le décalage par rapport au centre de la carte en pixels
    final dx = localPosition.dx - (mapSize.width / 2);
    final dy = localPosition.dy - (mapSize.height / 2);

    // Constantes pour la projection Web Mercator
    const double tileSize = 256.0;
    final scale = math.pow(2, camera.zoom);

    // Convertir le centre de la carte en pixels Mercator
    final centerX = (camera.center.longitude + 180) / 360 * tileSize * scale;
    final centerLatRad = camera.center.latitude * math.pi / 180;
    final centerY = (1 -
            math.log(math.tan(centerLatRad) + 1 / math.cos(centerLatRad)) /
                math.pi) /
        2 *
        tileSize *
        scale;

    // Calculer la position de la souris en pixels Mercator
    final mouseX = centerX + dx;
    final mouseY = centerY + dy;

    // Convertir les pixels Mercator en coordonnées géographiques
    final lng = mouseX / (tileSize * scale) * 360 - 180;
    final n = math.pi - 2 * math.pi * mouseY / (tileSize * scale);
    final lat = 180 / math.pi * math.atan(0.5 * (math.exp(n) - math.exp(-n)));

    final latLng = LatLng(lat, lng);

    // Debug: afficher les coordonnées calculées (moins fréquemment)
    if (kDebugMode && DateTime.now().millisecondsSinceEpoch % 500 < 50) {
      debugPrint('Mouse: local($dx, $dy) -> LatLng($lat, $lng)');
    }

    // Trouver le secteur sous le curseur
    int? newHoveredSectorId;
    for (final sector in _sectors) {
      final points = sector['points'] as List<LatLng>;
      if (_isPointInPolygon(latLng, points)) {
        newHoveredSectorId = sector['id'] as int;
        break;
      }
    }

    // Mettre à jour l'état selon le mode
    if (_mapMode == MapMode.deleting) {
      // Mode suppression
      if (newHoveredSectorId != _hoveredSectorId) {
        setState(() {
          _hoveredSectorId = newHoveredSectorId;
        });

        if (kDebugMode && newHoveredSectorId != null) {
          final sector =
              _sectors.firstWhere((s) => s['id'] == newHoveredSectorId);
          debugPrint(
              'Now hovering for delete: ${sector['name']} (ID: $newHoveredSectorId)');
        }
      }
    } else if (_mapMode == MapMode.editing) {
      // Mode édition - ne survoler que si aucun secteur n'est sélectionné
      if (_selectedSectorForEdit == null) {
        if (newHoveredSectorId != _hoveredSectorIdForEdit) {
          setState(() {
            _hoveredSectorIdForEdit = newHoveredSectorId;
          });

          if (kDebugMode && newHoveredSectorId != null) {
            final sector =
                _sectors.firstWhere((s) => s['id'] == newHoveredSectorId);
            debugPrint(
                'Now hovering for edit: ${sector['name']} (ID: $newHoveredSectorId)');
          }
        }
      }
    }
  }

  // Gérer le clic sur un secteur pour la suppression
  void _handleSectorClick(LatLng position) {
    // Trouver le secteur qui contient le point cliqué
    for (final sector in _sectors) {
      final points = sector['points'] as List<LatLng>;
      if (_isPointInPolygon(position, points)) {
        setState(() {
          _sectorToDeleteId = sector['id'] as int;
        });
        _showDeleteConfirmationDialog();
        break;
      }
    }
  }

  // Gérer le clic sur un secteur pour l'édition
  void _handleSectorClickForEdit(LatLng position) {
    // Trouver le secteur qui contient le point cliqué
    for (final sector in _sectors) {
      final points = sector['points'] as List<LatLng>;
      if (_isPointInPolygon(position, points)) {
        final sectorId = sector['id'] as int;
        final sectorModel =
            Hive.box<SectorModel>(AppKeys.sectorsBoxName).get(sectorId);

        if (sectorModel != null) {
          // Copier les points
          List<LatLng> magnetizedPoints = List<LatLng>.from(points);

          // Appliquer le magnétisme automatique à tous les points
          magnetizedPoints =
              _applyAutomaticMagnetism(magnetizedPoints, sectorId);

          setState(() {
            _selectedSectorForEdit = sectorModel;
            _editingPoints = magnetizedPoints;
            _originalPoints.clear();
            // Sauvegarder les points originaux (non magnétisés) pour pouvoir annuler
            for (int i = 0; i < points.length; i++) {
              _originalPoints[i] = points[i];
            }
            // Réinitialiser le survol quand un secteur est sélectionné
            _hoveredSectorIdForEdit = null;
          });

          // Vérifier si des points ont été magnétisés
          bool hasMagnetizedPoints = false;
          for (int i = 0; i < points.length; i++) {
            if (points[i] != magnetizedPoints[i]) {
              hasMagnetizedPoints = true;
              break;
            }
          }

          if (hasMagnetizedPoints) {
            _showEditInfoDialogWithMagnetism();
          } else {
            _showEditInfoDialog();
          }
        }
        break;
      }
    }
  }

  // Vérifier si un point est dans un polygone (algorithme ray-casting)
  bool _isPointInPolygon(LatLng point, List<LatLng> polygon) {
    int i, j = polygon.length - 1;
    bool oddNodes = false;

    for (i = 0; i < polygon.length; i++) {
      if ((polygon[i].latitude < point.latitude &&
                  polygon[j].latitude >= point.latitude ||
              polygon[j].latitude < point.latitude &&
                  polygon[i].latitude >= point.latitude) &&
          (polygon[i].longitude <= point.longitude ||
              polygon[j].longitude <= point.longitude)) {
        if (polygon[i].longitude +
                (point.latitude - polygon[i].latitude) /
                    (polygon[j].latitude - polygon[i].latitude) *
                    (polygon[j].longitude - polygon[i].longitude) <
            point.longitude) {
          oddNodes = !oddNodes;
        }
      }
      j = i;
    }

    return oddNodes;
  }

  // Vérifier si un point est sur le bord d'un polygone (avec tolérance)
  bool _isPointOnPolygonBorder(LatLng point, List<LatLng> polygon,
      {double tolerance = 5.0}) {
    for (int i = 0; i < polygon.length; i++) {
      final start = polygon[i];
      final end = polygon[(i + 1) % polygon.length];

      // Calculer la distance du point au segment
      final closestPoint = _getClosestPointOnSegment(point, start, end);
      final distance = _calculateDistance(point, closestPoint);

      // Si le point est proche du segment (dans la tolérance)
      if (distance <= tolerance) {
        return true;
      }
    }
    return false;
  }

  // Vérifier si un point est dans un secteur existant (mais pas sur le bord)
  bool _isPointInsideExistingSector(LatLng point) {
    for (final sector in _sectors) {
      final sectorPoints = sector['points'] as List<LatLng>;

      // Vérifier si le point est dans le polygone
      if (_isPointInPolygon(point, sectorPoints)) {
        // Vérifier s'il n'est PAS sur le bord (avec tolérance pour le magnétisme)
        if (!_isPointOnPolygonBorder(point, sectorPoints,
            tolerance: _snapDistance)) {
          return true; // Le point est vraiment à l'intérieur
        }
      }
    }
    return false;
  }

  // Vérifier si deux segments de droite se croisent
  bool _doSegmentsIntersect(LatLng p1, LatLng p2, LatLng p3, LatLng p4) {
    double x1 = p1.longitude;
    double y1 = p1.latitude;
    double x2 = p2.longitude;
    double y2 = p2.latitude;
    double x3 = p3.longitude;
    double y3 = p3.latitude;
    double x4 = p4.longitude;
    double y4 = p4.latitude;

    double denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);

    // Les lignes sont parallèles
    if (denom.abs() < 1e-10) {
      return false;
    }

    double t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / denom;
    double u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / denom;

    // Vérifier si l'intersection est sur les deux segments
    return t > 0 && t < 1 && u > 0 && u < 1;
  }

  // Vérifier si un polygone est valide (pas de croisements)
  bool _isValidPolygon(List<LatLng> points) {
    if (points.length < 3) return false;

    // Vérifier tous les segments contre tous les autres
    for (int i = 0; i < points.length; i++) {
      for (int j = i + 2; j < points.length; j++) {
        // Ne pas vérifier les segments adjacents
        if ((i == 0 && j == points.length - 1) || j == i + 1) continue;

        if (_doSegmentsIntersect(points[i], points[(i + 1) % points.length],
            points[j], points[(j + 1) % points.length])) {
          return false;
        }
      }
    }

    return true;
  }

  // Vérifier si deux polygones se chevauchent
  bool _doPolygonsOverlap(List<LatLng> polygon1, List<LatLng> polygon2) {
    // Tolérance pour considérer les secteurs comme adjacents et non chevauchants
    const double borderTolerance =
        5.0; // 5 mètres de tolérance pour les bordures
    const double pointTolerance =
        10.0; // 10 mètres de tolérance pour les points intérieurs

    // Compter les points vraiment à l'intérieur (pas sur les bords)
    int pointsInsidePolygon2 = 0;
    int pointsInsidePolygon1 = 0;

    // Vérifier les points du polygon1 dans polygon2
    for (final point in polygon1) {
      if (_isPointInPolygon(point, polygon2)) {
        // Vérifier si le point est vraiment à l'intérieur (pas sur le bord)
        if (!_isPointOnPolygonBorder(point, polygon2,
            tolerance: borderTolerance)) {
          // Vérifier la distance au bord le plus proche
          double minDistanceToBorder = double.infinity;
          for (int i = 0; i < polygon2.length; i++) {
            final start = polygon2[i];
            final end = polygon2[(i + 1) % polygon2.length];
            final closestPoint = _getClosestPointOnSegment(point, start, end);
            final distance = _calculateDistance(point, closestPoint);
            if (distance < minDistanceToBorder) {
              minDistanceToBorder = distance;
            }
          }

          // Si le point est vraiment à l'intérieur (pas trop proche du bord)
          if (minDistanceToBorder > pointTolerance) {
            pointsInsidePolygon2++;
          }
        }
      }
    }

    // Vérifier les points du polygon2 dans polygon1
    for (final point in polygon2) {
      if (_isPointInPolygon(point, polygon1)) {
        if (!_isPointOnPolygonBorder(point, polygon1,
            tolerance: borderTolerance)) {
          // Vérifier la distance au bord le plus proche
          double minDistanceToBorder = double.infinity;
          for (int i = 0; i < polygon1.length; i++) {
            final start = polygon1[i];
            final end = polygon1[(i + 1) % polygon1.length];
            final closestPoint = _getClosestPointOnSegment(point, start, end);
            final distance = _calculateDistance(point, closestPoint);
            if (distance < minDistanceToBorder) {
              minDistanceToBorder = distance;
            }
          }

          if (minDistanceToBorder > pointTolerance) {
            pointsInsidePolygon1++;
          }
        }
      }
    }

    // Il y a chevauchement seulement si une proportion significative de points est à l'intérieur
    // Augmenter le seuil pour être plus tolérant
    final threshold1 =
        polygon1.length >= 4 ? 3 : 2; // Au moins 3 points sur 4 (ou 2 sur 3)
    final threshold2 =
        polygon2.length >= 6 ? 3 : 2; // Adaptatif selon la taille

    if (pointsInsidePolygon2 >= threshold1 ||
        pointsInsidePolygon1 >= threshold2) {
      debugPrint('🚨 CHEVAUCHEMENT DÉTECTÉ - Points à l\'intérieur:');
      debugPrint(
          '   Points de polygon1 dans polygon2: $pointsInsidePolygon2 (seuil: $threshold1)');
      debugPrint(
          '   Points de polygon2 dans polygon1: $pointsInsidePolygon1 (seuil: $threshold2)');
      debugPrint(
          '   Polygon1 (nouveau secteur): ${polygon1.map((p) => '${p.latitude.toStringAsFixed(6)},${p.longitude.toStringAsFixed(6)}').join(' ')}');
      debugPrint(
          '   Polygon2 (secteur existant): ${polygon2.map((p) => '${p.latitude.toStringAsFixed(6)},${p.longitude.toStringAsFixed(6)}').join(' ')}');
      return true;
    }

    // Vérifier les intersections de segments qui ne sont pas des adjacences
    int realIntersections = 0;
    const double vertexTolerance =
        5.0; // Tolérance pour les sommets partagés (5m)

    for (int i = 0; i < polygon1.length; i++) {
      for (int j = 0; j < polygon2.length; j++) {
        final p1Start = polygon1[i];
        final p1End = polygon1[(i + 1) % polygon1.length];
        final p2Start = polygon2[j];
        final p2End = polygon2[(j + 1) % polygon2.length];

        // D'abord vérifier si les segments partagent un sommet
        final dist1 = _calculateDistance(p1Start, p2Start);
        final dist2 = _calculateDistance(p1Start, p2End);
        final dist3 = _calculateDistance(p1End, p2Start);
        final dist4 = _calculateDistance(p1End, p2End);

        // Si les segments partagent un sommet, ils ne peuvent pas se croiser vraiment
        if (dist1 < vertexTolerance ||
            dist2 < vertexTolerance ||
            dist3 < vertexTolerance ||
            dist4 < vertexTolerance) {
          // Les segments sont adjacents (partagent un sommet)
          continue;
        }

        if (_doSegmentsIntersect(p1Start, p1End, p2Start, p2End)) {
          // Vérifier si les segments sont alignés (partagent une partie)
          if (_areSegmentsAligned(p1Start, p1End, p2Start, p2End)) {
            debugPrint('   Intersection ignorée (segments alignés)');
            continue;
          }

          // C'est une vraie intersection
          realIntersections++;
          debugPrint('   VRAIE INTERSECTION détectée entre:');
          debugPrint(
              '     Seg1: ${p1Start.latitude.toStringAsFixed(6)},${p1Start.longitude.toStringAsFixed(6)} -> ${p1End.latitude.toStringAsFixed(6)},${p1End.longitude.toStringAsFixed(6)}');
          debugPrint(
              '     Seg2: ${p2Start.latitude.toStringAsFixed(6)},${p2Start.longitude.toStringAsFixed(6)} -> ${p2End.latitude.toStringAsFixed(6)},${p2End.longitude.toStringAsFixed(6)}');
        }
      }
    }

    // Il faut plusieurs vraies intersections pour considérer un chevauchement
    // Pour être plus tolérant avec les secteurs adjacents complexes
    if (realIntersections >= 3) {
      debugPrint('🚨 CHEVAUCHEMENT DÉTECTÉ - Intersections de segments:');
      debugPrint('   Nombre d\'intersections réelles: $realIntersections');
      debugPrint(
          '   Polygon1 (nouveau secteur): ${polygon1.map((p) => '${p.latitude.toStringAsFixed(6)},${p.longitude.toStringAsFixed(6)}').join(' ')}');
      debugPrint(
          '   Polygon2 (secteur existant): ${polygon2.map((p) => '${p.latitude.toStringAsFixed(6)},${p.longitude.toStringAsFixed(6)}').join(' ')}');
      return true;
    }

    return false;
  }

  // Vérifier si deux segments sont alignés (sur la même ligne)
  bool _areSegmentsAligned(LatLng p1, LatLng p2, LatLng p3, LatLng p4) {
    // Calculer la distance de p3 et p4 à la ligne définie par p1-p2
    final d3 = _pointToLineDistance(p3, p1, p2);
    final d4 = _pointToLineDistance(p4, p1, p2);

    // Calculer aussi la distance de p1 et p2 à la ligne définie par p3-p4
    final d1 = _pointToLineDistance(p1, p3, p4);
    final d2 = _pointToLineDistance(p2, p3, p4);

    // Tolérance plus large pour l'alignement (10m)
    const double alignmentTolerance = 10.0;

    // Les segments sont alignés si tous les points sont proches de la ligne opposée
    return (d3 < alignmentTolerance && d4 < alignmentTolerance) ||
        (d1 < alignmentTolerance && d2 < alignmentTolerance);
  }

  // Vérifier si deux segments sont adjacents (partagent une partie commune)

  // Calculer la distance d'un point à une ligne (définie par deux points)
  double _pointToLineDistance(LatLng point, LatLng lineStart, LatLng lineEnd) {
    final closestPoint = _getClosestPointOnSegment(point, lineStart, lineEnd);
    return _calculateDistance(point, closestPoint);
  }

  // Finaliser la création du secteur
  void _finalizeSectorCreation() {
    if (_drawingPoints.length < 3) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('Un secteur doit avoir au moins 3 points'),
          backgroundColor: Colors.orange,
        ),
      );
      return;
    }

    // Corriger automatiquement les points pour éviter les chevauchements
    debugPrint('📍 CRÉATION DE SECTEUR - Points originaux:');
    debugPrint(
        '   ${_drawingPoints.map((p) => '${p.latitude.toStringAsFixed(6)},${p.longitude.toStringAsFixed(6)}').join(' ')}');

    final correctedPoints = _correctPointsForAdjacency(_drawingPoints);

    // Vérifier si des points ont été corrigés
    bool pointsWereCorrected = false;
    for (int i = 0; i < _drawingPoints.length; i++) {
      if (_drawingPoints[i] != correctedPoints[i]) {
        pointsWereCorrected = true;
        break;
      }
    }

    if (pointsWereCorrected) {
      debugPrint('✏️ CORRECTION APPLIQUÉE - Points corrigés:');
      debugPrint(
          '   ${correctedPoints.map((p) => '${p.latitude.toStringAsFixed(6)},${p.longitude.toStringAsFixed(6)}').join(' ')}');
    }

    // Mettre à jour les points avec la version corrigée
    setState(() {
      _drawingPoints = correctedPoints;
    });

    // Informer l'utilisateur si des corrections ont été appliquées
    if (pointsWereCorrected) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text(
              'Les points ont été ajustés automatiquement pour éviter les chevauchements'),
          backgroundColor: Colors.blue,
          duration: Duration(seconds: 2),
        ),
      );
    }

    // Vérifier les chevauchements avec les secteurs existants
    bool hasOverlap = false;
    String? overlappingSectorName;

    for (final sector in _sectors) {
      final sectorPoints = sector['points'] as List<LatLng>;
      if (_doPolygonsOverlap(correctedPoints, sectorPoints)) {
        hasOverlap = true;
        overlappingSectorName = sector['name'] as String;
        debugPrint('❌ CHEVAUCHEMENT AVEC LE SECTEUR: $overlappingSectorName');
        break;
      }
    }

    if (hasOverlap) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text(
              'Le nouveau secteur chevauche avec le secteur "$overlappingSectorName"'),
          backgroundColor: Colors.red,
          duration: const Duration(seconds: 3),
        ),
      );
      return;
    }

    // Afficher le dialog de création
    _showSectorDialog();
  }

  // Afficher le dialog d'information pour l'édition
  void _showEditInfoDialog() {
    if (_selectedSectorForEdit == null) return;

    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(
            'Secteur "${_selectedSectorForEdit!.libelle}" sélectionné. Vous pouvez maintenant déplacer les points.'),
        backgroundColor: Colors.blue,
        duration: const Duration(seconds: 3),
      ),
    );
  }

  // Afficher le dialog d'information pour l'édition avec magnétisme
  void _showEditInfoDialogWithMagnetism() {
    if (_selectedSectorForEdit == null) return;

    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Secteur "${_selectedSectorForEdit!.libelle}" sélectionné.'),
            const SizedBox(height: 4),
            const Text(
              'Des points ont été automatiquement ajustés aux secteurs adjacents.',
              style: TextStyle(fontSize: 12),
            ),
          ],
        ),
        backgroundColor: Colors.orange,
        duration: const Duration(seconds: 4),
      ),
    );
  }

  // Afficher le dialog de confirmation de suppression
  Future<void> _showDeleteConfirmationDialog() async {
    if (_sectorToDeleteId == null) return;

    final sectorToDelete =
        _sectors.firstWhere((s) => s['id'] == _sectorToDeleteId);
    final sectorName = sectorToDelete['name'] as String;

    final result = await showDialog<bool>(
      context: context,
      barrierDismissible: false,
      builder: (context) => AlertDialog(
        title: Row(
          children: [
            Icon(Icons.warning, color: Colors.red),
            const SizedBox(width: 8),
            Text('Supprimer le secteur'),
          ],
        ),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Êtes-vous sûr de vouloir supprimer le secteur "$sectorName" ?',
              style: const TextStyle(fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 16),
            Container(
              padding: const EdgeInsets.all(12),
              decoration: BoxDecoration(
                color: Colors.orange.withOpacity(0.1),
                borderRadius: BorderRadius.circular(8),
                border: Border.all(color: Colors.orange.withOpacity(0.3)),
              ),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Row(
                    children: [
                      Icon(Icons.info_outline,
                          color: Colors.orange[700], size: 20),
                      const SizedBox(width: 8),
                      Text(
                        'Attention',
                        style: TextStyle(
                          color: Colors.orange[700],
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ],
                  ),
                  const SizedBox(height: 8),
                  Text(
                    '• Tous les passages à finaliser seront supprimés\n'
                    '• Les passages sans infos d\'habitant seront supprimés\n'
                    '• Les autres passages seront conservés sans secteur',
                    style: TextStyle(
                      color: Colors.orange[900],
                      fontSize: 13,
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
        actions: [
          TextButton(
            onPressed: () {
              Navigator.of(context).pop(false);
              setState(() {
                _mapMode = MapMode.view;
                _sectorToDeleteId = null;
              });
            },
            child: const Text('Annuler'),
          ),
          ElevatedButton.icon(
            onPressed: () => Navigator.of(context).pop(true),
            icon: const Icon(Icons.delete_forever),
            label: const Text('Supprimer'),
            style: ElevatedButton.styleFrom(
              backgroundColor: Colors.red,
              foregroundColor: Colors.white,
            ),
          ),
        ],
      ),
    );

    if (result == true) {
      await _deleteSector();
    } else {
      setState(() {
        _mapMode = MapMode.view;
        _sectorToDeleteId = null;
        _hoveredSectorId = null;
      });
    }
  }

  // Supprimer le secteur
  Future<void> _deleteSector() async {
    if (_sectorToDeleteId == null) return;

    try {
      // Afficher un indicateur de chargement
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Row(
            children: [
              SizedBox(
                width: 20,
                height: 20,
                child: CircularProgressIndicator(strokeWidth: 2),
              ),
              SizedBox(width: 16),
              Text('Suppression du secteur en cours...'),
            ],
          ),
          duration: Duration(seconds: 30),
        ),
      );

      final sectorRepository = SectorRepository();
      final result =
          await sectorRepository.deleteSectorFromApi(_sectorToDeleteId!);

      if (mounted) {
        ScaffoldMessenger.of(context).hideCurrentSnackBar();
      }

      if (result['status'] == 'success') {
        // Si le secteur supprimé était sélectionné, réinitialiser la sélection
        if (_selectedSectorId == _sectorToDeleteId) {
          setState(() {
            _selectedSectorId = null;
          });
        }

        // Recharger les secteurs et passages après la suppression
        _loadSectors();
        _loadPassages();
        _updateSectorCounts(); // Rafraîchir le comptage des membres

        // Message de succès simple
        if (mounted) {
          final deletedSector =
              _sectors.firstWhere((s) => s['id'] == _sectorToDeleteId);
          final deletedSectorName = deletedSector['name'] as String;
          final passagesDeleted = result['passages_deleted'] ?? 0;
          final passagesReassigned = result['passages_reassigned'] ?? 0;

          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(
              content: Text(
                  'Secteur "$deletedSectorName" supprimé. $passagesDeleted passages supprimés, $passagesReassigned réassignés.'),
              backgroundColor: Colors.green,
              duration: const Duration(seconds: 4),
            ),
          );
        }
      } else {
        final errorMessage =
            result['message'] ?? 'Erreur lors de la suppression du secteur';
        if (mounted) {
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(
              content: Text(errorMessage),
              backgroundColor: Colors.red,
            ),
          );
        }
      }
    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).hideCurrentSnackBar();
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text('Erreur: $e'),
            backgroundColor: Colors.red,
          ),
        );
      }
    } finally {
      setState(() {
        _mapMode = MapMode.view;
        _sectorToDeleteId = null;
        _hoveredSectorId = null;
      });
    }
  }

  // Afficher le dialog de création/modification de secteur
  Future<void> _showSectorDialog(
      {SectorModel? existingSector, List<List<double>>? coordinates}) async {
    final currentAmicale = CurrentAmicaleService.instance.currentAmicale;
    if (currentAmicale == null) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('Aucune amicale sélectionnée'),
          backgroundColor: Colors.red,
        ),
      );
      return;
    }

    // Sauvegarder le contexte du widget parent avant d'ouvrir le dialog
    final parentContext = context;

    // Préparer les coordonnées
    final finalCoordinates = coordinates ??
        (existingSector != null
            ? existingSector.getCoordinates()
            : _drawingPoints
                .map((point) => [point.latitude, point.longitude])
                .toList());

    await showDialog(
      context: parentContext,
      barrierDismissible: false,
      builder: (dialogContext) => SectorDialog(
        existingSector: existingSector,
        coordinates: finalCoordinates,
        onSave: (name, color, memberIds, updatePassages) async {
          // Le dialog se ferme automatiquement dans _handleSave()
          // Attendre un peu pour s'assurer que le dialog est fermé
          await Future.delayed(const Duration(milliseconds: 100));

          try {
            // Afficher un indicateur de chargement
            if (parentContext.mounted) {
              ScaffoldMessenger.of(parentContext).showSnackBar(
                const SnackBar(
                  content: Row(
                    children: [
                      SizedBox(
                        width: 20,
                        height: 20,
                        child: CircularProgressIndicator(strokeWidth: 2),
                      ),
                      SizedBox(width: 16),
                      Text('Enregistrement du secteur...'),
                    ],
                  ),
                  duration: Duration(seconds: 30),
                ),
              );
            }

            final sectorRepository = SectorRepository();
            int passagesCreated = 0;
            Map<String, dynamic> result;

            if (existingSector == null) {
              // Création d'un nouveau secteur
              // Convertir les coordonnées au format attendu par l'API : "lat/lng#lat/lng#..."
              final sectorString = '${finalCoordinates
                      .map((coord) => '${coord[0]}/${coord[1]}')
                      .join('#')}#'; // Ajouter un # final comme dans les exemples

              final newSector = SectorModel(
                id: 0, // L'API assignera l'ID
                libelle: name,
                color: color,
                sector: sectorString,
              );

              // Récupérer les informations nécessaires
              final currentUser = CurrentUserService.instance.currentUser;

              if (currentUser == null || currentUser.fkEntite == null) {
                throw Exception('Utilisateur non connecté ou sans entité');
              }

              // Récupérer l'opération courante
              final operationRepository = OperationRepository();
              final currentOperation =
                  operationRepository.getCurrentOperation();

              if (currentOperation == null) {
                throw Exception('Aucune opération active trouvée');
              }

              result = await sectorRepository.createSector(
                newSector,
                users: memberIds,
                fkEntite: currentUser.fkEntite!,
                operationId: currentOperation.id,
              );

              debugPrint('📋 RÉPONSE API CREATE:');
              debugPrint('   Status: ${result['status']}');
              debugPrint('   Result keys: ${result.keys.toList()}');

              if (result['status'] != 'success') {
                throw Exception(result['message'] ??
                    'Erreur lors de la création du secteur');
              }

              // Récupérer les statistiques et informations
              passagesCreated = result['passages_created'] ?? 0;

              // Traiter les passages retournés par l'API
              if (result['passages_sector'] != null) {
                debugPrint(
                    '🔄 Traitement de ${(result['passages_sector'] as List).length} passages retournés par l\'API...');
                await _processPassagesFromSectorApi(
                    result['passages_sector'] as List<dynamic>);
                debugPrint('✅ Passages traités avec succès');
              }

              // Les associations utilisateur-secteur sont déjà traitées dans SectorRepository.createSector()
              // Pas besoin de les traiter à nouveau ici

              // Recharger les secteurs et passages
              _loadSectors();
              _updateSectorCounts(); // Rafraîchir le comptage des membres

              // Présélectionner le secteur créé et afficher tous ses passages
              if (result.containsKey('sector') && result['sector'] != null) {
                final newSector = result['sector'] as SectorModel;

                setState(() {
                  // Sélectionner le secteur créé
                  _selectedSectorId = newSector.id;
                  _settingsBox.put('selectedSectorId', newSector.id);

                  // Mettre le filtre sur "Tous les passages"
                  _selectedPassageTypeFilter = -1;
                  _settingsBox.put('selectedPassageTypeFilter', -1);
                });

                // Recharger les passages avec le nouveau filtre
                _loadPassages();

                // Centrer la carte sur le nouveau secteur
                Future.delayed(const Duration(milliseconds: 500), () {
                  if (mounted) {
                    _centerMapOnSpecificSector(newSector.id);
                  }
                });
              }

              if (parentContext.mounted) {
                ScaffoldMessenger.of(parentContext).hideCurrentSnackBar();
              }

              // Message de succès simple pour la création
              if (mounted && parentContext.mounted) {
                String message = 'Secteur "$name" créé avec succès. ';
                if (passagesCreated > 0) {
                  message += '$passagesCreated passages créés.';
                }
                if (result['warning'] != null) {
                  message += ' Attention: ${result['warning']}';
                }

                ScaffoldMessenger.of(parentContext).showSnackBar(
                  SnackBar(
                    content: Text(message),
                    backgroundColor: result['warning'] != null
                        ? Colors.orange
                        : Colors.green,
                    duration: const Duration(seconds: 4),
                  ),
                );
              }
            } else {
              // Modification d'un secteur existant
              final sectorString = '${finalCoordinates
                      .map((coord) => '${coord[0]}/${coord[1]}')
                      .join('#')}#';

              final updatedSector = existingSector.copyWith(
                libelle: name,
                color: color,
                sector: sectorString,
              );

              result = await sectorRepository.updateSector(
                updatedSector,
                users: memberIds,
                chkAdressesChange: updatePassages ? 1 : 0,
              );

              if (result['status'] != 'success') {
                throw Exception(result['message'] ??
                    'Erreur lors de la modification du secteur');
              }

              // Traiter les passages retournés par l'API
              if (result['passages_sector'] != null) {
                debugPrint(
                    '🔄 Traitement de ${(result['passages_sector'] as List).length} passages retournés par l\'API après modification...');
                await _processPassagesFromSectorApi(
                    result['passages_sector'] as List<dynamic>);
                debugPrint('✅ Passages traités avec succès');
              }

              // Les associations utilisateur-secteur sont déjà traitées dans SectorRepository.updateSector()
              // Pas besoin de les traiter à nouveau ici

              // Recharger les secteurs et passages
              _loadSectors();
              _updateSectorCounts(); // Rafraîchir le comptage des membres

              // Présélectionner le secteur modifié et afficher tous ses passages
              setState(() {
                // Sélectionner le secteur modifié
                _selectedSectorId = existingSector.id;
                _settingsBox.put('selectedSectorId', existingSector.id);

                // Mettre le filtre sur "Tous les passages"
                _selectedPassageTypeFilter = -1;
                _settingsBox.put('selectedPassageTypeFilter', -1);
              });

              // Recharger les passages avec le nouveau filtre
              _loadPassages();

              // Centrer la carte sur le secteur modifié
              Future.delayed(const Duration(milliseconds: 500), () {
                if (mounted) {
                  _centerMapOnSpecificSector(existingSector.id);
                }
              });

              if (parentContext.mounted) {
                ScaffoldMessenger.of(parentContext).hideCurrentSnackBar();
              }

              // Message de succès simple pour la modification
              if (mounted && parentContext.mounted) {
                String message = 'Secteur "$name" modifié avec succès. ';
                final passagesUpdated = result['passages_updated'] ?? 0;
                final passagesCreated = result['passages_created'] ?? 0;
                final passagesOrphaned = result['passages_orphaned'] ?? 0;

                if (passagesUpdated > 0) {
                  message += '$passagesUpdated passages mis à jour. ';
                }
                if (passagesCreated > 0) {
                  message += '$passagesCreated nouveaux passages. ';
                }
                if (passagesOrphaned > 0) {
                  message += '$passagesOrphaned passages orphelins. ';
                }
                if (result['warning'] != null) {
                  message += ' Attention: ${result['warning']}';
                }

                ScaffoldMessenger.of(parentContext).showSnackBar(
                  SnackBar(
                    content: Text(message),
                    backgroundColor: result['warning'] != null
                        ? Colors.orange
                        : Colors.green,
                    duration: const Duration(seconds: 4),
                  ),
                );
              }
            }
          } catch (e) {
            if (parentContext.mounted) {
              ScaffoldMessenger.of(parentContext).hideCurrentSnackBar();
              ScaffoldMessenger.of(parentContext).showSnackBar(
                SnackBar(
                  content: Text('Erreur: $e'),
                  backgroundColor: Colors.red,
                ),
              );
            }
          } finally {
            // Réinitialiser le mode après la création/modification
            if (mounted) {
              setState(() {
                _mapMode = MapMode.view;
                _drawingPoints.clear();
                _editingPoints.clear();
              });
            }
          }
        },
      ),
    );
  }

  // Widget pour les boutons d'action
  Widget _buildActionButton({
    required IconData icon,
    required String tooltip,
    required VoidCallback? onPressed,
    Color color = Colors.blue,
    Color? iconColor,
  }) {
    return Container(
      decoration: BoxDecoration(
        shape: BoxShape.circle,
        boxShadow: [
          BoxShadow(
            color: Colors.black.withOpacity(0.2),
            blurRadius: 4,
            offset: const Offset(0, 2),
          ),
        ],
      ),
      child: FloatingActionButton(
        heroTag: tooltip, // Nécessaire pour éviter les conflits de hero tags
        onPressed: onPressed,
        backgroundColor: onPressed != null ? color : Colors.grey,
        tooltip: tooltip,
        mini: true,
        child: Icon(
          icon,
          color: iconColor ?? Colors.white,
        ),
      ),
    );
  }

  // Construire le menu contextuel selon le mode
  Widget _buildContextualMenu() {
    return Material(
      elevation: 4,
      borderRadius: BorderRadius.circular(8),
      child: Container(
        padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.circular(8),
        ),
        child: Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            if (_mapMode == MapMode.drawing) ...[
              // Menu pour le mode dessin
              if (_drawingPoints.isNotEmpty) ...[
                TextButton.icon(
                  onPressed: _undoLastPoint,
                  icon: const Icon(Icons.undo, size: 20),
                  label: const Text('Annuler dernier'),
                  style: TextButton.styleFrom(
                    foregroundColor: Colors.orange,
                  ),
                ),
                const SizedBox(width: 8),
              ],
              TextButton.icon(
                onPressed: _cancelDrawingMode,
                icon: const Icon(Icons.cancel, size: 20),
                label: const Text('Tout annuler'),
                style: TextButton.styleFrom(
                  foregroundColor: Colors.red,
                ),
              ),
            ] else if (_mapMode == MapMode.editing) ...[
              // Menu pour le mode édition
              if (_selectedSectorForEdit != null) ...[
                TextButton.icon(
                  onPressed: _saveEditedSector,
                  icon: const Icon(Icons.save, size: 20),
                  label: const Text('Enregistrer'),
                  style: TextButton.styleFrom(
                    foregroundColor: Colors.green,
                  ),
                ),
                const SizedBox(width: 8),
              ],
              TextButton.icon(
                onPressed: _cancelEditingMode,
                icon: const Icon(Icons.cancel, size: 20),
                label: const Text('Annuler'),
                style: TextButton.styleFrom(
                  foregroundColor: Colors.red,
                ),
              ),
            ] else if (_mapMode == MapMode.deleting) ...[
              // Menu pour le mode suppression
              TextButton.icon(
                onPressed: () {
                  setState(() {
                    _mapMode = MapMode.view;
                    _sectorToDeleteId = null;
                  });
                },
                icon: const Icon(Icons.cancel, size: 20),
                label: const Text('Annuler'),
                style: TextButton.styleFrom(
                  foregroundColor: Colors.red,
                ),
              ),
            ],
          ],
        ),
      ),
    );
  }

  // Construire la layer de dessin (polyline temporaire)
  List<Polyline> _buildDrawingLayer() {
    if (_drawingPoints.isEmpty && _editingPoints.isEmpty) return [];

    final List<Polyline> polylines = [];

    // Polyline pour le mode dessin
    if (_drawingPoints.isNotEmpty) {
      polylines.add(
        Polyline(
          points: _drawingPoints,
          strokeWidth: 3.0,
          color: Colors.blue.withOpacity(0.8),
        ),
      );
    }

    // Polyline pour le mode édition
    if (_editingPoints.isNotEmpty && _selectedSectorForEdit != null) {
      polylines.add(
        Polyline(
          points: [
            ..._editingPoints,
            _editingPoints.first
          ], // Fermer le polygone
          strokeWidth: 3.0,
          color: Colors.orange.withOpacity(0.8),
        ),
      );
    }

    return polylines;
  }

  // Construire les marqueurs pour les points de dessin
  List<Marker> _buildDrawingMarkers() {
    if (_drawingPoints.isEmpty) return [];

    final List<Marker> markers = [];

    // Ajouter les points principaux
    for (int i = 0; i < _drawingPoints.length; i++) {
      final point = _drawingPoints[i];
      final isFirst = i == 0;

      markers.add(
        Marker(
          point: point,
          width: isFirst ? 35.0 : 25.0,
          height: isFirst ? 35.0 : 25.0,
          child: Listener(
            onPointerDown: (event) {
              // Si c'est un clic droit (bouton 2) ou Ctrl+clic gauche
              if (event.buttons == 2 ||
                  (event.buttons == 1 &&
                      HardwareKeyboard.instance.isControlPressed)) {
                // Supprimer le point
                _removeDrawingPoint(i);
              } else if (event.buttons == 1) {
                // Clic gauche - commencer le drag du point
                // Note: La fermeture du polygone est gérée par _handleMapTap
                setState(() {
                  _draggingPointIndex = i;
                  _originalDragPosition = point;
                  _isDraggingPoint = true;
                });
              }
            },
            onPointerMove: (event) {
              if (_draggingPointIndex == i && _isDraggingPoint) {
                // Convertir les coordonnées de l'écran en coordonnées géographiques
                final RenderBox? renderBox =
                    context.findRenderObject() as RenderBox?;
                if (renderBox == null) return;

                final localPosition = renderBox.globalToLocal(event.position);
                final mapSize = renderBox.size;
                final camera = _mapController.camera;

                // Calculer le décalage par rapport au centre de la carte en pixels
                final dx = localPosition.dx - (mapSize.width / 2);
                final dy = localPosition.dy - (mapSize.height / 2);

                // Constantes pour la projection Web Mercator
                const double tileSize = 256.0;
                final scale = math.pow(2, camera.zoom);

                // Convertir le centre de la carte en pixels Mercator
                final centerX =
                    (camera.center.longitude + 180) / 360 * tileSize * scale;
                final centerY = (1 -
                        math.log(math.tan(
                                    camera.center.latitude * math.pi / 180) +
                                1 /
                                    math.cos(camera.center.latitude *
                                        math.pi /
                                        180)) /
                            math.pi) /
                    2 *
                    tileSize *
                    scale;

                // Calculer la nouvelle position en pixels Mercator
                final newX = centerX + dx;
                final newY = centerY + dy;

                // Convertir en coordonnées géographiques
                final lng = newX / tileSize / scale * 360 - 180;
                final n = math.pi - 2 * math.pi * newY / tileSize / scale;
                final lat = 180 /
                    math.pi *
                    math.atan(0.5 * (math.exp(n) - math.exp(-n)));

                final newPosition = LatLng(lat, lng);
                final snapPoint = _detectSnapPoint(newPosition);
                final finalPosition = snapPoint ?? newPosition;

                setState(() {
                  _drawingPoints[i] = finalPosition;
                  _snapPoint = snapPoint;
                });
              }
            },
            onPointerUp: (event) {
              if (_draggingPointIndex == i) {
                _handleDragEnd(i);
              }
            },
            child: MouseRegion(
              cursor: _draggingPointIndex == i
                  ? SystemMouseCursors.grabbing
                  : SystemMouseCursors.grab,
              child: AnimatedContainer(
                duration: const Duration(milliseconds: 200),
                decoration: BoxDecoration(
                  color: _draggingPointIndex == i
                      ? Colors.yellow
                      : (isFirst ? Colors.green : Colors.blue),
                  shape: BoxShape.circle,
                  border: Border.all(
                    color:
                        _draggingPointIndex == i ? Colors.orange : Colors.white,
                    width: _draggingPointIndex == i ? 3.0 : 2.0,
                  ),
                  boxShadow: [
                    BoxShadow(
                      color: Colors.black.withOpacity(0.3),
                      blurRadius: _draggingPointIndex == i ? 6 : 4,
                      offset: const Offset(0, 2),
                    ),
                  ],
                ),
                child: isFirst
                    ? const Center(
                        child: Text(
                          '1',
                          style: TextStyle(
                            color: Colors.white,
                            fontWeight: FontWeight.bold,
                            fontSize: 12,
                          ),
                        ),
                      )
                    : null,
              ),
            ),
          ),
        ),
      );
    }

    // Ajouter les midpoints si on a au moins 2 points
    if (_drawingPoints.length >= 2) {
      for (int i = 0; i < _drawingPoints.length; i++) {
        final start = _drawingPoints[i];
        final end = _drawingPoints[(i + 1) % _drawingPoints.length];

        // Ne pas ajouter de midpoint entre le dernier et le premier point si le polygone n'est pas fermé
        if (i == _drawingPoints.length - 1 && _drawingPoints.length < 3) {
          continue;
        }

        // Calculer le point milieu
        final midpoint = LatLng(
          (start.latitude + end.latitude) / 2,
          (start.longitude + end.longitude) / 2,
        );

        markers.add(Marker(
          point: midpoint,
          width: 15.0,
          height: 15.0,
          child: MouseRegion(
            cursor: SystemMouseCursors.click,
            onEnter: (_) {
              setState(() {
                _hoveredMidpointIndex = i;
              });
            },
            onExit: (_) {
              setState(() {
                _hoveredMidpointIndex = null;
              });
            },
            child: GestureDetector(
              onTap: () {
                // Insérer un nouveau point au milieu
                setState(() {
                  _drawingPoints.insert(i + 1, midpoint);
                  _hoveredMidpointIndex = null;
                });
              },
              child: AnimatedContainer(
                duration: const Duration(milliseconds: 200),
                decoration: BoxDecoration(
                  color: _hoveredMidpointIndex == i
                      ? Colors.blue.withOpacity(0.8)
                      : Colors.grey.withOpacity(0.5),
                  shape: BoxShape.circle,
                  border: Border.all(
                    color:
                        _hoveredMidpointIndex == i ? Colors.blue : Colors.grey,
                    width: 2.0,
                  ),
                ),
              ),
            ),
          ),
        ));
      }
    }

    return markers;
  }

  // Gérer le drag d'un point

  // Gérer la fin du drag
  void _handleDragEnd(int index) {
    // Vérifier si la position finale est valide
    if (!_isValidPolygon(_drawingPoints)) {
      // Annuler le déplacement
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('Le déplacement créerait une intersection'),
          backgroundColor: Colors.red,
          duration: Duration(seconds: 2),
        ),
      );
      setState(() {
        if (_originalDragPosition != null) {
          _drawingPoints[index] = _originalDragPosition!;
        }
        _draggingPointIndex = null;
        _originalDragPosition = null;
        _isDraggingPoint = false;
      });
    } else {
      setState(() {
        _draggingPointIndex = null;
        _originalDragPosition = null;
        _snapPoint = null;
      });

      // Réactiver le drag de la carte avec un petit délai pour éviter les conflits
      Future.delayed(const Duration(milliseconds: 100), () {
        if (mounted) {
          setState(() {
            _isDraggingPoint = false;
          });
        }
      });
    }
  }

  // Supprimer un point d'édition
  void _removeEditingPoint(int index) {
    if (_editingPoints.length <= 3) {
      // Ne pas permettre de supprimer si on a 3 points ou moins
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('Un secteur doit avoir au moins 3 points'),
          backgroundColor: Colors.orange,
          duration: Duration(seconds: 1),
        ),
      );
      return;
    }

    setState(() {
      _editingPoints.removeAt(index);
      // Si on supprime le point sélectionné, désélectionner
      if (_draggingPointIndex == index) {
        _draggingPointIndex = null;
      } else if (_draggingPointIndex != null && _draggingPointIndex! > index) {
        // Ajuster l'index si nécessaire
        _draggingPointIndex = _draggingPointIndex! - 1;
      }
    });

    // Afficher un message de confirmation
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(
        content: Text('Point supprimé'),
        backgroundColor: Colors.green,
        duration: Duration(seconds: 1),
      ),
    );
  }

  // Gérer le drag d'un point d'édition

  // Gérer la fin du drag d'un point d'édition
  void _handleEditingDragEnd(int index) {
    // Vérifier si la position finale est valide
    if (!_isValidPolygon(_editingPoints)) {
      // Annuler le déplacement
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('Le déplacement créerait une intersection'),
          backgroundColor: Colors.red,
          duration: Duration(seconds: 2),
        ),
      );
      setState(() {
        if (_originalDragPosition != null) {
          _editingPoints[index] = _originalDragPosition!;
        }
        _draggingPointIndex = null;
        _originalDragPosition = null;
        _isDraggingPoint = false;
      });
    } else {
      setState(() {
        _draggingPointIndex = null;
        _originalDragPosition = null;
        _snapPoint = null;
      });

      // Réactiver le drag de la carte avec un petit délai pour éviter les conflits
      Future.delayed(const Duration(milliseconds: 100), () {
        if (mounted) {
          setState(() {
            _isDraggingPoint = false;
          });
        }
      });
    }
  }

  // Construire les marqueurs pour le feedback visuel du magnétisme
  List<Marker> _buildSnapMarkers() {
    if (_snapPoint == null ||
        (_mapMode != MapMode.drawing && _mapMode != MapMode.editing)) return [];

    return [
      Marker(
        point: _snapPoint!,
        width: 20.0,
        height: 20.0,
        child: Container(
          decoration: BoxDecoration(
            color: Colors.orange.withOpacity(0.5),
            shape: BoxShape.circle,
            border: Border.all(
              color: Colors.orange,
              width: 2.0,
            ),
            boxShadow: [
              BoxShadow(
                color: Colors.orange.withOpacity(0.5),
                blurRadius: 8,
                spreadRadius: 2,
              ),
            ],
          ),
          child: const Center(
            child: Icon(
              Icons.adjust,
              size: 12,
              color: Colors.white,
            ),
          ),
        ),
      ),
    ];
  }

  // Construire les marqueurs pour l'édition
  List<Marker> _buildEditingMarkers() {
    if (_editingPoints.isEmpty || _selectedSectorForEdit == null) return [];

    final List<Marker> markers = [];

    // Ajouter les points principaux
    for (int i = 0; i < _editingPoints.length; i++) {
      final point = _editingPoints[i];
      final bool isDragging = _draggingPointIndex == i;
      final bool isHovered = _hoveredPointIndex == i;

      markers.add(Marker(
        point: point,
        width: 50.0, // Zone de détection plus large
        height: 50.0,
        child: Stack(
          alignment: Alignment.center,
          children: [
            // Zone de détection invisible mais interactive
            Listener(
              onPointerDown: (event) {
                // Si c'est un clic droit (bouton 2) ou Ctrl+clic gauche
                if (event.buttons == 2 ||
                    (event.buttons == 1 &&
                        HardwareKeyboard.instance.isControlPressed)) {
                  // Supprimer le point
                  _removeEditingPoint(i);
                } else if (event.buttons == 1) {
                  // Clic gauche : commencer le drag immédiatement
                  setState(() {
                    _draggingPointIndex = i;
                    _originalDragPosition = point;
                    _isDraggingPoint = true;
                  });
                }
              },
              onPointerMove: (event) {
                if (_draggingPointIndex == i && _isDraggingPoint) {
                  // Convertir les coordonnées de l'écran en coordonnées géographiques
                  final RenderBox? renderBox =
                      context.findRenderObject() as RenderBox?;
                  if (renderBox == null) return;

                  final localPosition = renderBox.globalToLocal(event.position);
                  final mapSize = renderBox.size;
                  final camera = _mapController.camera;

                  // Calculer le décalage par rapport au centre de la carte en pixels
                  final dx = localPosition.dx - (mapSize.width / 2);
                  final dy = localPosition.dy - (mapSize.height / 2);

                  // Constantes pour la projection Web Mercator
                  const double tileSize = 256.0;
                  final scale = math.pow(2, camera.zoom);

                  // Convertir le centre de la carte en pixels Mercator
                  final centerX =
                      (camera.center.longitude + 180) / 360 * tileSize * scale;
                  final centerY = (1 -
                          math.log(math.tan(
                                      camera.center.latitude * math.pi / 180) +
                                  1 /
                                      math.cos(camera.center.latitude *
                                          math.pi /
                                          180)) /
                              math.pi) /
                      2 *
                      tileSize *
                      scale;

                  // Calculer la nouvelle position en pixels Mercator
                  final newX = centerX + dx;
                  final newY = centerY + dy;

                  // Convertir en coordonnées géographiques
                  final lng = newX / tileSize / scale * 360 - 180;
                  final n = math.pi - 2 * math.pi * newY / tileSize / scale;
                  final lat = 180 /
                      math.pi *
                      math.atan(0.5 * (math.exp(n) - math.exp(-n)));

                  final newPosition = LatLng(lat, lng);
                  final snapPoint = _detectSnapPoint(newPosition);
                  final finalPosition = snapPoint ?? newPosition;

                  setState(() {
                    _editingPoints[i] = finalPosition;
                    _snapPoint = snapPoint;
                  });
                }
              },
              onPointerUp: (event) {
                if (_draggingPointIndex == i) {
                  _handleEditingDragEnd(i);
                }
              },
              child: MouseRegion(
                cursor: isDragging
                    ? SystemMouseCursors.grabbing
                    : SystemMouseCursors.grab,
                onEnter: (_) {
                  setState(() {
                    _hoveredPointIndex = i;
                  });
                },
                onExit: (_) {
                  setState(() {
                    _hoveredPointIndex = null;
                  });
                },
                child: Container(
                  width: 50,
                  height: 50,
                  color: Colors.transparent,
                ),
              ),
            ),
            // Point visible au centre avec animation
            IgnorePointer(
              child: AnimatedContainer(
                duration: const Duration(milliseconds: 200),
                width: isDragging ? 30 : (isHovered ? 28 : 25),
                height: isDragging ? 30 : (isHovered ? 28 : 25),
                decoration: BoxDecoration(
                  color: isDragging ? Colors.yellow : Colors.orange,
                  shape: BoxShape.circle,
                  border: Border.all(
                    color: isDragging ? Colors.orange : Colors.white,
                    width: isDragging ? 3.0 : 2.0,
                  ),
                  boxShadow: [
                    BoxShadow(
                      color: Colors.black.withOpacity(0.3),
                      blurRadius: isDragging ? 8 : (isHovered ? 6 : 4),
                      offset: const Offset(0, 2),
                    ),
                    if (isHovered && !isDragging)
                      BoxShadow(
                        color: Colors.orange.withOpacity(0.3),
                        blurRadius: 15,
                        spreadRadius: 2,
                      ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ));
    }

    // Ajouter les midpoints si on a au moins 2 points
    if (_editingPoints.length >= 2) {
      for (int i = 0; i < _editingPoints.length; i++) {
        final start = _editingPoints[i];
        final end = _editingPoints[(i + 1) % _editingPoints.length];

        // Calculer le point milieu
        final midpoint = LatLng(
          (start.latitude + end.latitude) / 2,
          (start.longitude + end.longitude) / 2,
        );

        markers.add(Marker(
          point: midpoint,
          width: 15.0,
          height: 15.0,
          child: MouseRegion(
            cursor: SystemMouseCursors.click,
            onEnter: (_) {
              setState(() {
                _hoveredMidpointIndex = i;
              });
            },
            onExit: (_) {
              setState(() {
                _hoveredMidpointIndex = null;
              });
            },
            child: GestureDetector(
              onTap: () {
                // Détecter le magnétisme pour le nouveau point
                final snapPoint = _detectSnapPoint(midpoint);
                final finalPosition = snapPoint ?? midpoint;

                // Insérer un nouveau point au milieu avec magnétisme
                setState(() {
                  _editingPoints.insert(i + 1, finalPosition);
                  _hoveredMidpointIndex = null;
                  _snapPoint = null;
                });
              },
              child: AnimatedContainer(
                duration: const Duration(milliseconds: 200),
                decoration: BoxDecoration(
                  color: _hoveredMidpointIndex == i
                      ? Colors.orange.withOpacity(0.8)
                      : Colors.grey.withOpacity(0.5),
                  shape: BoxShape.circle,
                  border: Border.all(
                    color: _hoveredMidpointIndex == i
                        ? Colors.orange
                        : Colors.grey,
                    width: 2.0,
                  ),
                ),
              ),
            ),
          ),
        ));
      }
    }

    return markers;
  }

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<Box<PassageModel>>(
      valueListenable:
          Hive.box<PassageModel>(AppKeys.passagesBoxName).listenable(),
      builder: (context, passagesBox, child) {
        // Charger les passages en temps réel de manière sécurisée
        // Les secteurs ne sont rechargés que lors de création/modification
        WidgetsBinding.instance.addPostFrameCallback((_) {
          _loadPassagesFromBox(passagesBox);
        });

        return Stack(
              children: [
                // Carte MapBox avec gestion du tap et du survol
                Positioned.fill(
                    child: MouseRegion(
                  cursor: (_mapMode == MapMode.deleting &&
                              _hoveredSectorId != null) ||
                          (_mapMode == MapMode.editing &&
                              _hoveredSectorIdForEdit != null &&
                              _selectedSectorForEdit == null)
                      ? SystemMouseCursors.click
                      : SystemMouseCursors.basic,
                  onHover: (event) {
                    // Gérer le survol
                    if (_mapMode == MapMode.deleting) {
                      _handleMouseHover(event);
                    } else if (_mapMode == MapMode.editing) {
                      // En mode édition, gérer à la fois le survol des secteurs et le magnétisme
                      _handleMouseHover(event);
                      if (_editingPoints.isNotEmpty) {
                        // Détecter le magnétisme en temps réel pendant l'édition
                        _handleEditingHover(event);
                      }
                    } else if (_mapMode == MapMode.drawing &&
                        _drawingPoints.isNotEmpty) {
                      // Détecter le magnétisme en temps réel pendant le dessin
                      _handleDrawingHover(event);
                    }
                  },
                  onExit: (event) {
                    // Réinitialiser le survol quand la souris quitte la carte
                    if (_hoveredSectorId != null ||
                        _hoveredSectorIdForEdit != null) {
                      setState(() {
                        _hoveredSectorId = null;
                        _hoveredSectorIdForEdit = null;
                      });
                    }
                  },
                  child: MapboxMap(
                    initialPosition: _currentPosition,
                    initialZoom: _currentZoom,
                    mapController: _mapController,
                    disableDrag: _isDraggingPoint,
                    // Utiliser les tuiles IGN (Plan ou Ortho selon le choix utilisateur)
                    tileSource: _tileSource,
                    labelMarkers: _buildSectorLabels(),
                    markers: [
                      ..._buildMarkers(),
                      ..._buildDrawingMarkers(),
                      ..._buildEditingMarkers(),
                      ..._buildSnapMarkers(),
                    ],
                    polygons: _buildPolygons(),
                    polylines: _buildDrawingLayer(),
                    showControls: true,
                    onMapEvent: (event) {
                      if (event is MapEventMove) {
                        final displayedZoom = event.camera.zoom;

                        // Afficher l'indicateur de zoom si le niveau a changé
                        if ((displayedZoom - _currentZoom).abs() > 0.01) {
                          _showZoomIndicatorTemporarily();
                        }

                        // Mettre à jour les variables sans setState() immédiat
                        _currentPosition = event.camera.center;
                        _currentZoom = displayedZoom;

                        // Annuler le timer précédent
                        _mapMoveDebounceTimer?.cancel();

                        // Lancer un nouveau timer de 300ms pour debouncer
                        _mapMoveDebounceTimer = Timer(const Duration(milliseconds: 300), () {
                          if (mounted) {
                            // setState uniquement après 300ms sans mouvement
                            setState(() {
                              // Les variables sont déjà à jour
                            });
                            _saveSettings();
                          }
                        });
                      } else if (event is MapEventTap &&
                          (_mapMode == MapMode.drawing ||
                              _mapMode == MapMode.deleting ||
                              _mapMode == MapMode.editing)) {
                        _handleMapTap(event.tapPosition);
                      }
                    },
                  ),
                )),

                // Bouton switch IGN Plan / Ortho en haut à droite (visible pour tous)
                Positioned(
                  right: 16,
                  top: 16,
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.end,
                    children: [
                      // Bouton switch IGN Plan / Ortho
                      // L'icône montre l'action (vers quoi on bascule), pas l'état actuel
                      _buildActionButton(
                        icon: _tileSource == TileSource.ignPlan
                            ? Icons.satellite_alt  // En mode plan → afficher satellite pour basculer
                            : Icons.map_outlined,   // En mode ortho → afficher plan pour basculer
                        tooltip: _tileSource == TileSource.ignPlan
                            ? 'Passer en vue satellite'
                            : 'Passer en vue plan',
                        color: Colors.white,
                        iconColor: Colors.blueGrey[700],
                        onPressed: () {
                          setState(() {
                            _tileSource = _tileSource == TileSource.ignPlan
                                ? TileSource.ignOrtho
                                : TileSource.ignPlan;
                            _settingsBox.put('mapTileSource', _tileSource.name);
                            debugPrint('🗺️ MapPage: Source tuiles changée = $_tileSource');
                          });
                        },
                      ),
                      // Espacement avant les boutons admin
                      if (kIsWeb && canEditSectors) const SizedBox(height: 16),
                      // Boutons admin (création, modification, suppression de secteurs)
                      if (kIsWeb && canEditSectors) ...[
                        // Bouton Créer
                        _buildActionButton(
                          icon: Icons.pentagon_outlined,
                          tooltip: 'Créer un secteur',
                          color: _mapMode == MapMode.drawing
                              ? Colors.green
                              : Colors.blue,
                          onPressed: _mapMode == MapMode.view
                              ? _startDrawingMode
                              : null,
                        ),
                        const SizedBox(height: 8),
                        // Bouton Modifier
                        _buildActionButton(
                          icon: Icons.polyline_outlined,
                          tooltip: 'Modifier un secteur',
                          color: _mapMode == MapMode.editing
                              ? Colors.orange
                              : Colors.blue,
                          onPressed: _mapMode == MapMode.view
                              ? _startEditingMode
                              : null,
                        ),
                        const SizedBox(height: 8),
                        // Bouton Supprimer
                        _buildActionButton(
                          icon: Icons.delete_forever,
                          tooltip: 'Supprimer un secteur',
                          color: _mapMode == MapMode.deleting
                              ? Colors.red
                              : Colors.white,
                          iconColor: _mapMode == MapMode.deleting
                              ? Colors.white
                              : Colors.red,
                          onPressed: _mapMode == MapMode.view
                              ? _startDeletingMode
                              : null,
                        ),
                      ],
                    ],
                  ),
                ),

                // Menu contextuel (apparaît selon le mode) - Web uniquement et admin seulement
                if (kIsWeb && canEditSectors && _mapMode != MapMode.view)
                  Positioned(
                    right: 80,
                    top: 16,
                    child: _buildContextualMenu(),
                  ),

                // Bouton Ma position en bas à gauche
                Positioned(
                  left: 16,
                  bottom: 16,
                  child: _buildActionButton(
                    icon: Icons.my_location,
                    tooltip: 'Ma position',
                    onPressed: () {
                      _getUserLocation();
                    },
                  ),
                ),

                // Combobox de sélection de secteurs
                Positioned(
                  left: 16,
                  top: 16,
                  child: Material(
                    elevation: 4,
                    borderRadius: BorderRadius.circular(8),
                    child: Container(
                      padding: const EdgeInsets.symmetric(
                          horizontal: 12, vertical: 4),
                      width: 220, // Largeur fixe pour accommoder les noms longs
                      decoration: BoxDecoration(
                        color: Colors.white.withOpacity(0.95),
                        borderRadius: BorderRadius.circular(8),
                      ),
                      child: Row(
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          const Icon(Icons.location_on,
                              size: 18, color: Colors.blue),
                          const SizedBox(width: 8),
                          Expanded(
                            child: DropdownButton<int?>(
                              value: _selectedSectorId,
                              hint: const Text('Tous les secteurs'),
                              isExpanded: true,
                              underline:
                                  Container(), // Supprimer la ligne sous le dropdown
                              icon: const Icon(Icons.arrow_drop_down,
                                  color: Colors.blue),
                              items: _sectorItems,
                              onChanged: (int? sectorId) {
                                setState(() {
                                  _selectedSectorId = sectorId;

                                  // Si un secteur est sélectionné et qu'aucun type de passage n'est sélectionné,
                                  // auto-sélectionner "Tous les passages"
                                  if (sectorId != null && _selectedPassageTypeFilter == null) {
                                    _selectedPassageTypeFilter = -1; // Tous les passages
                                    _settingsBox.put('selectedPassageTypeFilter', -1);
                                  }
                                });

                                if (sectorId != null) {
                                  _centerMapOnSpecificSector(sectorId);
                                } else {
                                  // Si "Tous les secteurs" est sélectionné
                                  _centerMapOnSectors();
                                  // Recharger tous les passages sans filtrage par secteur
                                  _loadPassages();
                                }
                              },
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                ),

                // Combobox de sélection de type de passage (admin seulement)
                if (isAdmin)
                  Positioned(
                    left: 16,
                    top: 76,
                    child: Material(
                      elevation: 4,
                      borderRadius: BorderRadius.circular(8),
                      child: Container(
                        padding: const EdgeInsets.symmetric(
                            horizontal: 12, vertical: 4),
                        width: 220,
                        decoration: BoxDecoration(
                          color: Colors.white.withOpacity(0.95),
                          borderRadius: BorderRadius.circular(8),
                        ),
                        child: Row(
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            const Icon(Icons.filter_list,
                                size: 18, color: Colors.orange),
                            const SizedBox(width: 8),
                            Expanded(
                              child: DropdownButton<int?>(
                                value: _selectedPassageTypeFilter,
                                hint: const Text('Aucun passage'),
                                isExpanded: true,
                                underline: Container(),
                                icon: const Icon(Icons.arrow_drop_down,
                                    color: Colors.orange),
                                items: _passageTypeItems,
                                onChanged: (int? typeId) {
                                  setState(() {
                                    _selectedPassageTypeFilter = typeId;
                                  });

                                  // Sauvegarder dans Hive
                                  _settingsBox.put('selectedPassageTypeFilter', typeId);

                                  // Recharger les passages avec le nouveau filtre
                                  _loadPassages();
                                },
                              ),
                            ),
                          ],
                        ),
                      ),
                    ),
                  ),

                // Carte d'aide pour le mode création de secteur - Web uniquement
                if (kIsWeb && _mapMode == MapMode.drawing)
                  Positioned(
                    left: 16,
                    bottom: 16,
                    child: _buildHelpCard(),
                  ),

                // Carte d'aide pour le mode suppression de secteur - Web uniquement
                if (kIsWeb && _mapMode == MapMode.deleting)
                  Positioned(
                    left: 16,
                    bottom: 16,
                    child: _buildDeleteHelpCard(),
                  ),

                // Carte d'aide pour le mode édition de secteur - Web uniquement
                if (kIsWeb && _mapMode == MapMode.editing)
                  Positioned(
                    left: 16,
                    bottom: 16,
                    child: _buildEditHelpCard(),
                  ),

                // Indicateur de zoom éphémère (2 secondes)
                if (_showZoomIndicator)
                  Positioned(
                    bottom: 24,
                    left: 0,
                    right: 0,
                    child: Center(
                      child: AnimatedOpacity(
                        opacity: _showZoomIndicator ? 1.0 : 0.0,
                        duration: const Duration(milliseconds: 300),
                        child: Container(
                          padding: const EdgeInsets.symmetric(
                            horizontal: 20,
                            vertical: 8,
                          ),
                          decoration: BoxDecoration(
                            color: Colors.blue.withOpacity(0.3),
                            borderRadius: BorderRadius.circular(20),
                          ),
                          child: Text(
                            _currentZoom.toStringAsFixed(0),
                            style: TextStyle(
                              color: Colors.blue.shade700,
                              fontSize: 32,
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                        ),
                      ),
                    ),
                  ),
              ],
            );
      },
    );
  }

  // Méthode pour traiter les passages retournés par l'API sans effacer tous les passages existants
  Future<void> _processPassagesFromSectorApi(List<dynamic> passagesData) async {
    try {
      if (passagesData.isEmpty) {
        debugPrint('Aucun passage à traiter');
        return;
      }

      final passageRepository = PassageRepository();
      final List<PassageModel> passagesToSave = [];

      for (final passageData in passagesData) {
        try {
          final passage = PassageModel.fromJson(
              Map<String, dynamic>.from(passageData as Map));
          passagesToSave.add(passage);
        } catch (e) {
          debugPrint('Erreur lors du traitement d\'un passage: $e');
          // Continuer avec les autres passages
        }
      }

      if (passagesToSave.isNotEmpty) {
        await passageRepository.savePassages(passagesToSave);
        debugPrint('${passagesToSave.length} passages sauvegardés dans Hive');
      }
    } catch (e) {
      debugPrint('Erreur lors du traitement des passages: $e');
    }
  }
}
