import 'dart:async';
import 'package:flutter/material.dart';
import 'package:geosector_app/core/theme/app_theme.dart';
import 'package:flutter/services.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import 'package:geolocator/geolocator.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:flutter_compass/flutter_compass.dart';
import 'package:geosector_app/core/constants/app_keys.dart';
import 'package:geosector_app/core/data/models/passage_model.dart';
import 'package:geosector_app/core/services/current_amicale_service.dart';
import 'package:geosector_app/presentation/widgets/passage_form_dialog.dart';
import 'package:geosector_app/presentation/widgets/passages/passages_list_widget.dart';
import 'package:geosector_app/presentation/widgets/grouped_passages_dialog.dart';
import 'package:geosector_app/presentation/widgets/mapbox_map.dart' show TileSource;
import 'package:geosector_app/app.dart';
import 'package:geosector_app/core/utils/api_exception.dart';

class UserFieldModePage extends StatefulWidget {
  const UserFieldModePage({super.key});

  @override
  State<UserFieldModePage> createState() => _UserFieldModePageState();
}

class _UserFieldModePageState extends State<UserFieldModePage>
    with TickerProviderStateMixin {
  // Controllers
  final MapController _mapController = MapController();
  final TextEditingController _searchController = TextEditingController();

  // Animation controllers pour le clignotement
  late AnimationController _gpsBlinkController;
  late AnimationController _networkBlinkController;
  late Animation<double> _gpsBlinkAnimation;
  late Animation<double> _networkBlinkAnimation;

  // Position et tracking
  Position? _currentPosition;
  StreamSubscription<Position>? _positionStreamSubscription;
  Timer? _qualityUpdateTimer;

  // Qualité des signaux
  double _gpsAccuracy = 999;
  List<ConnectivityResult> _connectivityResult = [ConnectivityResult.none];
  bool _isGpsEnabled = false;

  // Filtrage et recherche
  String _searchQuery = '';
  List<PassageModel> _nearbyPassages = [];

  // État de chargement
  bool _isLoading = true;
  bool _locationPermissionGranted = false;
  String _statusMessage = '';

  // Listener pour les changements de la box passages
  Box<PassageModel>? _passagesBox;

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

  // Mode boussole (Android/iOS uniquement)
  bool _compassModeEnabled = false;
  StreamSubscription<CompassEvent>? _compassSubscription;
  double _currentHeading = 0.0;

  @override
  void initState() {
    super.initState();
    _initializeAnimations();
    _loadTileSourceSetting();

    // Écouter les changements de la Hive box passages pour rafraîchir la carte
    _passagesBox = Hive.box<PassageModel>(AppKeys.passagesBoxName);
    _passagesBox?.listenable().addListener(_onPassagesChanged);

    if (kIsWeb) {
      // Sur web, utiliser une position simulée pour éviter le blocage
      _initializeWebMode();
    } else {
      // Sur mobile, utiliser le GPS réel
      _checkPermissionsAndStartTracking();
      _startQualityMonitoring();
    }
  }

  // Callback appelé quand la box passages change
  void _onPassagesChanged() {
    if (mounted) {
      _updateNearbyPassages();
    }
  }

  // Charger le paramètre de source des tuiles depuis Hive
  Future<void> _loadTileSourceSetting() async {
    if (!Hive.isBoxOpen(AppKeys.settingsBoxName)) {
      _settingsBox = await Hive.openBox(AppKeys.settingsBoxName);
    } else {
      _settingsBox = Hive.box(AppKeys.settingsBoxName);
    }

    final savedTileSource = _settingsBox?.get('mapTileSource');
    if (savedTileSource != null && mounted) {
      setState(() {
        _tileSource = TileSource.values.firstWhere(
          (t) => t.name == savedTileSource,
          orElse: () => TileSource.ignPlan,
        );
      });
      debugPrint('FieldMode: Source tuiles chargée = $_tileSource');
    }
  }

  void _initializeWebMode() async {
    // Essayer d'obtenir la position réelle depuis le navigateur
    try {
      setState(() {
        _statusMessage = "Demande d'autorisation de géolocalisation...";
      });

      // Demander la permission et obtenir la position
      final position = await Geolocator.getCurrentPosition(
        locationSettings: const LocationSettings(
          accuracy: LocationAccuracy.high,
        ),
      );

      setState(() {
        _currentPosition = position;
        _gpsAccuracy = position.accuracy;
        _isGpsEnabled = true;
        _connectivityResult = [ConnectivityResult.wifi];
        _isLoading = false;
        _locationPermissionGranted = true;
        _statusMessage = "";
      });

      // Charger les passages proches de la position réelle
      _updateNearbyPassages();

      // Démarrer le suivi de position même sur web
      _startLocationTracking();
    } catch (e) {
      debugPrint('Erreur géolocalisation web: $e');

      // Essayer d'utiliser les coordonnées GPS de l'amicale
      double fallbackLat = 46.603354; // Centre de la France par défaut
      double fallbackLng = 1.888334;
      String statusMessage = "Position approximative";

      try {
        final amicale = CurrentAmicaleService.instance.currentAmicale;
        if (amicale != null &&
            amicale.gpsLat.isNotEmpty &&
            amicale.gpsLng.isNotEmpty) {
          final amicaleLat = double.tryParse(amicale.gpsLat);
          final amicaleLng = double.tryParse(amicale.gpsLng);

          if (amicaleLat != null && amicaleLng != null) {
            fallbackLat = amicaleLat;
            fallbackLng = amicaleLng;
            statusMessage = "Position de l'amicale";
            debugPrint(
                'Utilisation des coordonnées de l\'amicale: $fallbackLat, $fallbackLng');
          }
        }
      } catch (amicaleError) {
        debugPrint('Erreur récupération coordonnées amicale: $amicaleError');
      }

      // Utiliser la position de fallback (amicale ou centre France)
      setState(() {
        _currentPosition = Position(
          latitude: fallbackLat,
          longitude: fallbackLng,
          timestamp: DateTime.now(),
          accuracy: 100.0,
          altitude: 0.0,
          heading: 0.0,
          speed: 0.0,
          speedAccuracy: 0.0,
          altitudeAccuracy: 0.0,
          headingAccuracy: 0.0,
        );
        _gpsAccuracy = 100.0;
        _isGpsEnabled = false;
        _connectivityResult = [ConnectivityResult.wifi];
        _isLoading = false;
        _locationPermissionGranted = false;
        _statusMessage = statusMessage;
      });

      _updateNearbyPassages();
    }
  }

  void _initializeAnimations() {
    // Animation pour GPS faible/perdu
    _gpsBlinkController = AnimationController(
      duration: const Duration(milliseconds: 500),
      vsync: this,
    );
    _gpsBlinkAnimation = Tween<double>(
      begin: 1.0,
      end: 0.3,
    ).animate(CurvedAnimation(
      parent: _gpsBlinkController,
      curve: Curves.easeInOut,
    ));

    // Animation pour réseau faible/perdu
    _networkBlinkController = AnimationController(
      duration: const Duration(milliseconds: 500),
      vsync: this,
    );
    _networkBlinkAnimation = Tween<double>(
      begin: 1.0,
      end: 0.3,
    ).animate(CurvedAnimation(
      parent: _networkBlinkController,
      curve: Curves.easeInOut,
    ));
  }

  Future<void> _checkPermissionsAndStartTracking() async {
    // Les permissions GPS sont déjà vérifiées obligatoirement dans splash_page.dart
    // On peut donc directement commencer le tracking
    setState(() {
      _locationPermissionGranted = true;
    });
    _startLocationTracking();
  }

  void _startLocationTracking() {
    const locationSettings = LocationSettings(
      accuracy: LocationAccuracy.high,
      distanceFilter: 5, // Mise à jour tous les 5 mètres
    );

    _positionStreamSubscription = Geolocator.getPositionStream(
      locationSettings: locationSettings,
    ).listen((Position position) {
      setState(() {
        _currentPosition = position;
        _gpsAccuracy = position.accuracy;
        _isGpsEnabled = true;
        _isLoading = false;
      });

      _updateNearbyPassages();
      _updateBlinkAnimations();

      // Centrer la carte sur la nouvelle position
      _mapController.move(LatLng(position.latitude, position.longitude), 17);
    }, onError: (error) {
      setState(() {
        _isGpsEnabled = false;
      });
    });
  }

  void _startQualityMonitoring() {
    // Mise à jour toutes les 5 secondes
    _qualityUpdateTimer =
        Timer.periodic(const Duration(seconds: 5), (timer) async {
      // Vérifier la connexion réseau
      final connectivityResult = await Connectivity().checkConnectivity();
      setState(() {
        _connectivityResult = connectivityResult;
      });

      // Vérifier si le GPS est activé
      final isLocationServiceEnabled =
          await Geolocator.isLocationServiceEnabled();
      setState(() {
        _isGpsEnabled = isLocationServiceEnabled;
      });

      _updateBlinkAnimations();
    });
  }

  void _updateBlinkAnimations() {
    // GPS: clignoter si précision > 30m ou GPS désactivé
    if (!_isGpsEnabled || _gpsAccuracy > 30) {
      _gpsBlinkController.repeat(reverse: true);
    } else {
      _gpsBlinkController.stop();
      _gpsBlinkController.value = 1.0;
    }

    // Réseau: clignoter si connexion faible ou absente
    if (_connectivityResult.contains(ConnectivityResult.none) ||
        _connectivityResult.contains(ConnectivityResult.mobile)) {
      _networkBlinkController.repeat(reverse: true);
    } else {
      _networkBlinkController.stop();
      _networkBlinkController.value = 1.0;
    }
  }

  void _updateNearbyPassages() {
    if (_currentPosition == null) return;

    final passagesBox = Hive.box<PassageModel>(AppKeys.passagesBoxName);
    final allPassages = passagesBox.values.toList(); // Tous les types de passages

    // Calculer les distances et trier
    final passagesWithDistance = allPassages.map((passage) {
      // Convertir les coordonnées GPS string en double
      final double lat = double.tryParse(passage.gpsLat) ?? 0;
      final double lng = double.tryParse(passage.gpsLng) ?? 0;

      final distance = _calculateDistance(
        _currentPosition!.latitude,
        _currentPosition!.longitude,
        lat,
        lng,
      );
      return MapEntry(passage, distance);
    }).toList();

    passagesWithDistance.sort((a, b) => a.value.compareTo(b.value));

    final newNearbyPassages = passagesWithDistance
        .where((entry) => entry.value <= 500) // Max 500m
        .map((entry) => entry.key)
        .toList();

    // Ne setState que si les passages ont vraiment changé
    if (!_arePassagesEqual(_nearbyPassages, newNearbyPassages)) {
      setState(() {
        _nearbyPassages = newNearbyPassages;
      });
    }
  }

  // Comparer deux listes de passages pour éviter les setState inutiles
  bool _arePassagesEqual(List<PassageModel> oldPassages, List<PassageModel> 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) => '${p.id}_${p.fkType}').toSet();
    final newKeys = newPassages.map((p) => '${p.id}_${p.fkType}').toSet();

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

  double _calculateDistance(
      double lat1, double lon1, double lat2, double lon2) {
    const distance = Distance();
    return distance.as(
      LengthUnit.Meter,
      LatLng(lat1, lon1),
      LatLng(lat2, lon2),
    );
  }

  void _recenterMap() {
    if (_currentPosition != null) {
      _mapController.move(
        LatLng(_currentPosition!.latitude, _currentPosition!.longitude),
        17,
      );
      HapticFeedback.lightImpact();
    }
  }

  void _openPassageForm(PassageModel passage) {
    showDialog(
      context: context,
      builder: (context) => PassageFormDialog(
        passage: passage,
        title: 'Modifier le passage',
        readOnly: false,
        passageRepository: passageRepository,
        userRepository: userRepository,
        operationRepository: operationRepository,
        amicaleRepository: amicaleRepository,
        onSuccess: () {
          // Rafraîchir les passages après modification
          _updateNearbyPassages();
        },
      ),
    );
  }

  // Afficher la dialog groupée pour les immeubles
  void _showGroupedPassagesDialog(PassageModel referencePassage) {
    showDialog(
      context: context,
      builder: (context) => GroupedPassagesDialog(
        referencePassage: referencePassage,
        isAdmin: false, // Mode terrain = utilisateur simple
      ),
    );
  }

  // Vérifier si l'amicale autorise la suppression des passages
  bool _canDeletePassages() {
    try {
      final amicale = CurrentAmicaleService.instance.currentAmicale;
      if (amicale != null) {
        return amicale.chkUserDeletePass == true;
      }
    } catch (e) {
      debugPrint(
          'Erreur lors de la vérification des permissions de suppression: $e');
    }
    return false;
  }

  // Afficher le dialog de confirmation de suppression
  void _showDeleteConfirmationDialog(PassageModel passage) {
    final TextEditingController confirmController = TextEditingController();
    final String streetNumber = passage.numero;
    final String fullAddress =
        '${passage.numero} ${passage.rueBis} ${passage.rue}'.trim();

    showDialog(
      context: context,
      barrierDismissible: false,
      builder: (BuildContext dialogContext) {
        return AlertDialog(
          title: const Row(
            children: [
              Icon(Icons.warning, color: Colors.red, size: 28),
              SizedBox(width: 8),
              Text('Confirmation de suppression'),
            ],
          ),
          content: SingleChildScrollView(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  'ATTENTION : Cette action est irréversible !',
                  style: TextStyle(
                    fontWeight: FontWeight.bold,
                    color: Colors.red,
                    fontSize: AppTheme.r(context, 16),
                  ),
                ),
                const SizedBox(height: 16),
                Text(
                  'Vous êtes sur le point de supprimer définitivement le passage :',
                  style: TextStyle(color: Colors.grey[800]),
                ),
                const SizedBox(height: 8),
                Container(
                  padding: const EdgeInsets.all(12),
                  decoration: BoxDecoration(
                    color: Colors.grey[100],
                    borderRadius: BorderRadius.circular(8),
                    border: Border.all(color: Colors.grey[300]!),
                  ),
                  child: Text(
                    fullAddress.isEmpty ? 'Adresse inconnue' : fullAddress,
                    style: TextStyle(
                      fontWeight: FontWeight.w600,
                      fontSize: AppTheme.r(context, 14),
                    ),
                  ),
                ),
                const SizedBox(height: 20),
                const Text(
                  'Pour confirmer la suppression, veuillez saisir le numéro de rue de ce passage :',
                  style: TextStyle(fontWeight: FontWeight.w500),
                ),
                const SizedBox(height: 12),
                TextField(
                  controller: confirmController,
                  decoration: InputDecoration(
                    labelText: 'Numéro de rue',
                    hintText: streetNumber.isNotEmpty
                        ? 'Ex: $streetNumber'
                        : 'Saisir le numéro',
                    border: const OutlineInputBorder(),
                    prefixIcon: const Icon(Icons.home),
                  ),
                  keyboardType: TextInputType.text,
                  textCapitalization: TextCapitalization.characters,
                ),
              ],
            ),
          ),
          actions: [
            TextButton(
              onPressed: () {
                confirmController.dispose();
                Navigator.of(dialogContext).pop();
              },
              child: const Text('Annuler'),
            ),
            ElevatedButton(
              onPressed: () async {
                // Vérifier que le numéro saisi correspond
                final enteredNumber = confirmController.text.trim();
                if (enteredNumber.isEmpty) {
                  ScaffoldMessenger.of(context).showSnackBar(
                    const SnackBar(
                      content: Text('Veuillez saisir le numéro de rue'),
                      backgroundColor: Colors.orange,
                    ),
                  );
                  return;
                }

                if (streetNumber.isNotEmpty &&
                    enteredNumber.toUpperCase() != streetNumber.toUpperCase()) {
                  ScaffoldMessenger.of(context).showSnackBar(
                    const SnackBar(
                      content: Text('Le numéro de rue ne correspond pas'),
                      backgroundColor: Colors.red,
                    ),
                  );
                  return;
                }

                // Fermer le dialog
                confirmController.dispose();
                Navigator.of(dialogContext).pop();

                // Effectuer la suppression
                await _deletePassage(passage);
              },
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.red,
                foregroundColor: Colors.white,
              ),
              child: const Text('Supprimer définitivement'),
            ),
          ],
        );
      },
    );
  }

  // Supprimer un passage
  Future<void> _deletePassage(PassageModel passage) async {
    try {
      // Appeler le repository pour supprimer via l'API
      final success = await passageRepository.deletePassageViaApi(passage.id);

      if (success && mounted) {
        ApiException.showSuccess(context, 'Passage supprimé avec succès');

        // Rafraîchir la liste des passages
        _updateNearbyPassages();
      } else if (mounted) {
        ApiException.showError(
            context, Exception('Erreur lors de la suppression'));
      }
    } catch (e) {
      debugPrint('Erreur suppression passage: $e');
      if (mounted) {
        ApiException.showError(context, e);
      }
    }
  }

  @override
  void dispose() {
    _positionStreamSubscription?.cancel();
    _qualityUpdateTimer?.cancel();
    _compassSubscription?.cancel();
    _gpsBlinkController.dispose();
    _networkBlinkController.dispose();
    _searchController.dispose();
    _passagesBox?.listenable().removeListener(_onPassagesChanged);
    super.dispose();
  }

  // Activer/désactiver le mode boussole (Android/iOS uniquement)
  void _toggleCompassMode() {
    if (kIsWeb) return; // Pas de boussole sur web

    setState(() {
      _compassModeEnabled = !_compassModeEnabled;
    });

    if (_compassModeEnabled) {
      // Activer l'écoute de la boussole
      _compassSubscription = FlutterCompass.events?.listen((CompassEvent event) {
        if (event.heading != null && mounted) {
          setState(() {
            _currentHeading = event.heading!;
          });
          // Faire pivoter la carte selon la direction
          _mapController.rotate(-_currentHeading);
        }
      });
      debugPrint('FieldMode: Mode boussole activé');
    } else {
      // Désactiver l'écoute et remettre la carte vers le nord
      _compassSubscription?.cancel();
      _compassSubscription = null;
      _mapController.rotate(0);
      debugPrint('FieldMode: Mode boussole désactivé');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey[100],
      appBar: AppBar(
        title: Row(
          children: [
            const Text('Mode terrain'),
            if (_currentPosition != null) ...[
              const SizedBox(width: 16),
              Expanded(
                child: Container(
                  padding:
                      const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
                  decoration: BoxDecoration(
                    color: Colors.white.withOpacity(0.2),
                    borderRadius: BorderRadius.circular(12),
                  ),
                  child: Text(
                    kIsWeb
                        ? (_locationPermissionGranted
                            ? 'GPS: ${_currentPosition!.latitude.toStringAsFixed(4)}, ${_currentPosition!.longitude.toStringAsFixed(4)}'
                            : _statusMessage.isNotEmpty
                                ? _statusMessage
                                : 'Position approximative')
                        : '',
                    style: TextStyle(
                      fontSize: AppTheme.r(context, 12),
                      fontWeight: FontWeight.normal,
                    ),
                    overflow: TextOverflow.ellipsis,
                  ),
                ),
              ),
            ],
          ],
        ),
        backgroundColor: Colors.green,
        foregroundColor: Colors.white,
        elevation: 0,
        actions: [
          // Indicateur GPS
          _buildGpsIndicator(),
          const SizedBox(width: 8),
          // Indicateur réseau
          _buildNetworkIndicator(),
          const SizedBox(width: 16),
        ],
      ),
      body: _isLoading
          ? const Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  CircularProgressIndicator(),
                  SizedBox(height: 16),
                  Text('Recherche de votre position...'),
                ],
              ),
            )
          : Column(
              children: [
                // Carte (40% de la hauteur)
                SizedBox(
                  height: MediaQuery.of(context).size.height * 0.4,
                  child: _buildMap(),
                ),
                // Barre de recherche
                Container(
                  color: Colors.white,
                  padding: const EdgeInsets.all(12),
                  child: TextField(
                    controller: _searchController,
                    decoration: InputDecoration(
                      hintText: 'Rechercher une rue...',
                      prefixIcon: const Icon(Icons.search),
                      suffixIcon: _searchQuery.isNotEmpty
                          ? IconButton(
                              icon: const Icon(Icons.clear),
                              onPressed: () {
                                setState(() {
                                  _searchController.clear();
                                  _searchQuery = '';
                                });
                              },
                            )
                          : null,
                      border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(30),
                        borderSide: BorderSide.none,
                      ),
                      filled: true,
                      fillColor: Colors.grey[100],
                      contentPadding:
                          const EdgeInsets.symmetric(horizontal: 20),
                    ),
                    onChanged: (value) {
                      setState(() {
                        _searchQuery = value.toLowerCase();
                      });
                    },
                  ),
                ),
                // En-tête de la liste
                Container(
                  color: Colors.white,
                  padding:
                      const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                  child: Row(
                    children: [
                      Icon(Icons.location_on,
                          color: Colors.green[600], size: 20),
                      const SizedBox(width: 8),
                      Text(
                        '${_getFilteredPassages().length} passage${_getFilteredPassages().length > 1 ? 's' : ''} à proximité',
                        style: TextStyle(
                          fontWeight: FontWeight.w600,
                          color: Colors.grey[800],
                        ),
                      ),
                    ],
                  ),
                ),
                // Liste des passages (reste de la hauteur)
                Expanded(
                  child: _buildPassagesList(),
                ),
              ],
            ),
    );
  }

  Widget _buildGpsIndicator() {
    IconData icon;
    Color color;
    String tooltip;

    if (!_isGpsEnabled) {
      icon = Icons.gps_off;
      color = Colors.black54;
      tooltip = 'GPS désactivé';
    } else if (_gpsAccuracy <= 5) {
      icon = Icons.gps_fixed;
      color = Colors.green;
      tooltip = 'GPS: Excellent (${_gpsAccuracy.toStringAsFixed(0)}m)';
    } else if (_gpsAccuracy <= 15) {
      icon = Icons.gps_fixed;
      color = Colors.yellow[700]!;
      tooltip = 'GPS: Bon (${_gpsAccuracy.toStringAsFixed(0)}m)';
    } else if (_gpsAccuracy <= 30) {
      icon = Icons.gps_not_fixed;
      color = Colors.orange;
      tooltip = 'GPS: Moyen (${_gpsAccuracy.toStringAsFixed(0)}m)';
    } else {
      icon = Icons.gps_not_fixed;
      color = Colors.red;
      tooltip = 'GPS: Faible (${_gpsAccuracy.toStringAsFixed(0)}m)';
    }

    return AnimatedBuilder(
      animation: _gpsBlinkAnimation,
      builder: (context, child) {
        return Tooltip(
          message: tooltip,
          child: Opacity(
            opacity: _gpsBlinkAnimation.value,
            child: Container(
              padding: const EdgeInsets.all(8),
              decoration: BoxDecoration(
                color: color.withOpacity(0.2),
                borderRadius: BorderRadius.circular(20),
              ),
              child: Row(
                mainAxisSize: MainAxisSize.min,
                children: [
                  Icon(icon, color: color, size: 20),
                  const SizedBox(width: 4),
                  Text(
                    '${_gpsAccuracy.toStringAsFixed(0)}m',
                    style: TextStyle(
                        color: color,
                        fontWeight: FontWeight.bold,
                        fontSize: AppTheme.r(context, 12)),
                  ),
                ],
              ),
            ),
          ),
        );
      },
    );
  }

  Widget _buildNetworkIndicator() {
    IconData icon;
    Color color;
    String label;
    String tooltip;

    // Utiliser le premier élément de la liste pour déterminer le type de connexion
    final primaryResult = _connectivityResult.firstWhere(
      (result) => result != ConnectivityResult.none,
      orElse: () => ConnectivityResult.none
    );

    switch (primaryResult) {
      case ConnectivityResult.wifi:
        icon = Icons.wifi;
        color = Colors.green;
        label = 'WiFi';
        tooltip = 'Connexion WiFi';
        break;
      case ConnectivityResult.ethernet:
        icon = Icons.cable;
        color = Colors.green;
        label = '4G';
        tooltip = 'Connexion Ethernet';
        break;
      case ConnectivityResult.mobile:
        icon = Icons.signal_cellular_alt;
        color = Colors.yellow[700]!;
        label = '3G';
        tooltip = 'Connexion mobile';
        break;
      case ConnectivityResult.none:
      default:
        icon = Icons.signal_cellular_off;
        color = Colors.red;
        label = 'Hors ligne';
        tooltip = 'Aucune connexion';
        break;
    }

    return AnimatedBuilder(
      animation: _networkBlinkAnimation,
      builder: (context, child) {
        return Tooltip(
          message: tooltip,
          child: Opacity(
            opacity: _networkBlinkAnimation.value,
            child: Container(
              padding: const EdgeInsets.all(8),
              decoration: BoxDecoration(
                color: color.withOpacity(0.2),
                borderRadius: BorderRadius.circular(20),
              ),
              child: Row(
                mainAxisSize: MainAxisSize.min,
                children: [
                  Icon(icon, color: color, size: 20),
                  const SizedBox(width: 4),
                  Text(
                    label,
                    style: TextStyle(
                        color: color,
                        fontWeight: FontWeight.bold,
                        fontSize: AppTheme.r(context, 12)),
                  ),
                ],
              ),
            ),
          ),
        );
      },
    );
  }

  Widget _buildMap() {
    if (_currentPosition == null) {
      return Container(
        color: Colors.grey[200],
        child: const Center(
          child: CircularProgressIndicator(),
        ),
      );
    }

    return Stack(
      children: [
        FlutterMap(
            mapController: _mapController,
            options: MapOptions(
              initialCenter: LatLng(
                  _currentPosition!.latitude, _currentPosition!.longitude),
              initialZoom: 17,
              maxZoom: 19,
              minZoom: 10,
              interactionOptions: InteractionOptions(
                enableMultiFingerGestureRace: true,
                // Permettre la rotation uniquement si le mode boussole est activé
                flags: _compassModeEnabled
                    ? InteractiveFlag.all
                    : InteractiveFlag.all & ~InteractiveFlag.rotate,
              ),
            ),
            children: [
              TileLayer(
                // Utiliser les tuiles IGN (Plan ou Ortho selon le choix utilisateur)
                urlTemplate: _tileSource == TileSource.ignOrtho
                    ? 'https://data.geopf.fr/wmts?'
                        'REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0'
                        '&TILEMATRIXSET=PM'
                        '&LAYER=ORTHOIMAGERY.ORTHOPHOTOS'
                        '&STYLE=normal'
                        '&FORMAT=image/jpeg'
                        '&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}'
                    : 'https://data.geopf.fr/wmts?'
                        'REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0'
                        '&TILEMATRIXSET=PM'
                        '&LAYER=GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2'
                        '&STYLE=normal'
                        '&FORMAT=image/png'
                        '&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}',
                userAgentPackageName: 'app3.geosector.fr',
                maxNativeZoom: 19,
                maxZoom: 20,
                minZoom: 7,
              ),
              // Markers des passages
              MarkerLayer(
                markers: _buildPassageMarkers(),
              ),
              // Position actuelle
              MarkerLayer(
                markers: [
                  Marker(
                    point: LatLng(_currentPosition!.latitude,
                        _currentPosition!.longitude),
                    width: 30,
                    height: 30,
                    child: Container(
                      decoration: BoxDecoration(
                        shape: BoxShape.circle,
                        color: Colors.blue,
                        border: Border.all(color: Colors.white, width: 3),
                        boxShadow: [
                          BoxShadow(
                            color: Colors.blue.withOpacity(0.3),
                            blurRadius: 10,
                            spreadRadius: 5,
                          ),
                        ],
                      ),
                      child: const Icon(
                        Icons.person_pin,
                        color: Colors.white,
                        size: 16,
                      ),
                    ),
                  ),
                ],
              ),
            ],
        ),
        // Bouton recentrage (bas gauche)
        Positioned(
          bottom: 16,
          left: 16,
          child: FloatingActionButton.small(
            backgroundColor: Colors.white,
            foregroundColor: Colors.green[700],
            onPressed: _recenterMap,
            child: const Icon(Icons.my_location),
          ),
        ),
        // Boutons haut droite (IGN + Boussole)
        Positioned(
          top: 16,
          right: 16,
          child: Column(
            children: [
              // Bouton switch IGN Plan / Ortho
              FloatingActionButton.small(
                heroTag: 'tileSource',
                backgroundColor: Colors.white,
                foregroundColor: Colors.green[700],
                tooltip: _tileSource == TileSource.ignPlan
                    ? 'Passer en vue satellite'
                    : 'Passer en vue plan',
                onPressed: () {
                  setState(() {
                    _tileSource = _tileSource == TileSource.ignPlan
                        ? TileSource.ignOrtho
                        : TileSource.ignPlan;
                  });
                  // Sauvegarder le choix
                  _settingsBox?.put('mapTileSource', _tileSource.name);
                  debugPrint('FieldMode: Source tuiles = $_tileSource');
                },
                // L'icône montre l'action (vers quoi on bascule), pas l'état actuel
                child: Icon(
                  _tileSource == TileSource.ignPlan
                      ? Icons.satellite_alt  // En mode plan → afficher satellite pour basculer
                      : Icons.map_outlined,   // En mode ortho → afficher plan pour basculer
                ),
              ),
              // Bouton mode boussole (uniquement sur mobile)
              if (!kIsWeb) ...[
                const SizedBox(height: 8),
                FloatingActionButton.small(
                  heroTag: 'compass',
                  backgroundColor: _compassModeEnabled ? Colors.green[700] : Colors.white,
                  foregroundColor: _compassModeEnabled ? Colors.white : Colors.green[700],
                  tooltip: _compassModeEnabled
                      ? 'Désactiver le mode boussole'
                      : 'Activer le mode boussole',
                  onPressed: _toggleCompassMode,
                  child: Icon(
                    _compassModeEnabled ? Icons.explore : Icons.explore_outlined,
                  ),
                ),
              ],
            ],
          ),
        ),
      ],
    );
  }

  // Assombrir une couleur pour les bordures
  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();
  }

  List<Marker> _buildPassageMarkers() {
    if (_currentPosition == null) return [];

    final List<Marker> markers = [];

    // 1. Séparer les passages immeubles (fkHabitat=2) des autres
    final buildingPassages = <String, List<Map<String, dynamic>>>{};
    final individualPassages = <PassageModel>[];

    for (final passage in _nearbyPassages) {
      if (passage.fkHabitat == 2) {
        // Créer une clé unique basée sur l'adresse complète
        final addressKey = '${passage.numero}|${passage.rueBis}|${passage.rue}|${passage.ville}';

        // Convertir les coordonnées GPS string en double
        final double lat = double.tryParse(passage.gpsLat) ?? 0;
        final double lng = double.tryParse(passage.gpsLng) ?? 0;

        buildingPassages.putIfAbsent(addressKey, () => []);
        buildingPassages[addressKey]!.add({
          'model': passage,
          'position': LatLng(lat, lng),
          'id': passage.id,
        });
      } else {
        individualPassages.add(passage);
      }
    }

    // 2. Créer les markers individuels (fkHabitat != 2) - Cercles
    for (final passage in individualPassages) {
      // Déterminer la couleur selon le type de passage
      Color fillColor = Colors.grey; // Couleur par défaut

      if (AppKeys.typesPassages.containsKey(passage.fkType)) {
        final typeInfo = AppKeys.typesPassages[passage.fkType]!;

        if (passage.fkType == 2) {
          // Type 2 (À finaliser) : adapter la couleur selon nbPassages
          if (passage.nbPassages == 0) {
            fillColor = Color(typeInfo['couleur1'] as int);
          } else if (passage.nbPassages == 1) {
            fillColor = Color(typeInfo['couleur2'] as int);
          } else {
            fillColor = Color(typeInfo['couleur3'] as int);
          }
        } else {
          // Autres types : utiliser couleur2 par défaut
          fillColor = Color(typeInfo['couleur2'] as int);
        }
      }

      // Bordure : version assombrie de la couleur de remplissage
      final borderColor = _darkenColor(fillColor, 0.3);

      // Convertir les coordonnées GPS string en double
      final double lat = double.tryParse(passage.gpsLat) ?? 0;
      final double lng = double.tryParse(passage.gpsLng) ?? 0;

      markers.add(
        Marker(
          point: LatLng(lat, lng),
          width: 40,
          height: 40,
          child: GestureDetector(
            onTap: () => _openPassageForm(passage),
            child: Container(
              decoration: BoxDecoration(
                shape: BoxShape.circle,
                color: fillColor,
                border: Border.all(color: borderColor, width: 3),
                boxShadow: [
                  BoxShadow(
                    color: Colors.black.withOpacity(0.2),
                    blurRadius: 4,
                    offset: const Offset(0, 2),
                  ),
                ],
              ),
              child: Center(
                child: Text(
                  '${passage.numero}${(passage.rueBis.isNotEmpty) ? passage.rueBis.substring(0, 1).toLowerCase() : ''}',
                  style: TextStyle(
                    // Texte noir sur fond clair, blanc sur fond foncé
                    color: fillColor.computeLuminance() > 0.5
                        ? Colors.black
                        : Colors.white,
                    fontWeight: FontWeight.bold,
                    fontSize: AppTheme.r(context, 12),
                  ),
                  textAlign: TextAlign.center,
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis,
                ),
              ),
            ),
          ),
        ),
      );
    }

    // 3. Créer les markers groupés (carrés avec dégradé blanc→vert selon avancement)
    for (final entry in buildingPassages.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;
  }

  List<Map<String, dynamic>> _getFilteredPassages() {
    // Filtrer d'abord par recherche si nécessaire
    List<PassageModel> filtered = _searchQuery.isEmpty
        ? _nearbyPassages
        : _nearbyPassages.where((passage) {
            final address = '${passage.numero} ${passage.rueBis} ${passage.rue}'
                .trim()
                .toLowerCase();
            return address.contains(_searchQuery);
          }).toList();

    // Convertir au format attendu par PassagesListWidget avec distance
    return filtered.map((passage) {
      // Calculer la distance
      final double lat = double.tryParse(passage.gpsLat) ?? 0;
      final double lng = double.tryParse(passage.gpsLng) ?? 0;

      final distance = _currentPosition != null
          ? _calculateDistance(
              _currentPosition!.latitude,
              _currentPosition!.longitude,
              lat,
              lng,
            )
          : 0.0;

      // Construire l'adresse complète
      final String address =
          '${passage.numero} ${passage.rueBis} ${passage.rue}'.trim();

      // Convertir le montant
      double amount = 0.0;
      try {
        if (passage.montant.isNotEmpty) {
          String montantStr = passage.montant.replaceAll(',', '.');
          amount = double.tryParse(montantStr) ?? 0.0;
        }
      } catch (e) {
        // Ignorer les erreurs de conversion
      }

      return {
        'id': passage.id,
        'address': address.isEmpty ? 'Adresse inconnue' : address,
        'amount': amount,
        'date': passage.passedAt ?? DateTime.now(),
        'type': passage.fkType,
        'payment': passage.fkTypeReglement,
        'name': passage.name,
        'notes': passage.remarque,
        'hasReceipt': passage.nomRecu.isNotEmpty,
        'hasError': passage.emailErreur.isNotEmpty,
        'fkUser': passage.fkUser,
        'distance': distance, // Ajouter la distance pour le tri et l'affichage
        'nbPassages': passage.nbPassages, // Pour la couleur de l'indicateur
        'isOwnedByCurrentUser': passage.fkUser ==
            userRepository
                .getCurrentUser()
                ?.opeUserId, // Comparer avec ope_users.id
        // Garder les données originales pour l'édition
        'numero': passage.numero,
        'rueBis': passage.rueBis,
        'rue': passage.rue,
        'ville': passage.ville,
      };
    }).toList();
  }

  Widget _buildPassagesList() {
    final filteredPassages = _getFilteredPassages();

    return Container(
      color: Colors.white,
      child: PassagesListWidget(
        passages: filteredPassages,
        showActions: true,
        showAddButton: true, // Activer le bouton de création
        onPassageSelected: null,
        onPassageEdit: (passage) {
          // Retrouver le PassageModel original pour l'édition
          final passageId = passage['id'] as int;
          final originalPassage = _nearbyPassages.firstWhere(
            (p) => p.id == passageId,
            orElse: () => _nearbyPassages.first,
          );
          _openPassageForm(originalPassage);
        },
        onAddPassage: () async {
          // Ouvrir le dialogue de création de passage
          await showDialog(
            context: context,
            barrierDismissible: false,
            builder: (BuildContext context) {
              return PassageFormDialog(
                title: 'Nouveau passage',
                passageRepository: passageRepository,
                userRepository: userRepository,
                operationRepository: operationRepository,
                amicaleRepository: amicaleRepository,
                onSuccess: () {
                  // Le widget se rafraîchira automatiquement via ValueListenableBuilder
                },
              );
            },
          );
        },
        onPassageDelete: _canDeletePassages()
            ? (passage) {
                // Retrouver le PassageModel original pour la suppression
                final passageId = passage['id'] as int;
                final originalPassage = _nearbyPassages.firstWhere(
                  (p) => p.id == passageId,
                  orElse: () => _nearbyPassages.first,
                );
                _showDeleteConfirmationDialog(originalPassage);
              }
            : null,
      ),
    );
  }
}
