import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map_cache/flutter_map_cache.dart';
import 'package:dio_cache_interceptor_hive_store/dio_cache_interceptor_hive_store.dart';
import 'package:path_provider/path_provider.dart';
import 'package:latlong2/latlong.dart';
import 'package:geosector_app/core/constants/app_keys.dart';
import 'package:geosector_app/core/services/api_service.dart'; // Import du service singleton

/// Enum représentant les différentes sources de tuiles disponibles
enum TileSource {
  /// Tuiles Mapbox (par défaut)
  mapbox,
  /// Tuiles OpenStreetMap
  openStreetMap,
  /// Tuiles IGN Plan (carte routière française)
  ignPlan,
  /// Tuiles IGN Ortho Photos (photos aériennes)
  ignOrtho,
}

/// Widget de carte réutilisable utilisant Mapbox
///
/// Ce widget encapsule un FlutterMap avec des tuiles Mapbox et fournit
/// des fonctionnalités pour afficher des marqueurs, des polygones et des contrôles.
class MapboxMap extends StatefulWidget {
  /// Position initiale de la carte
  final LatLng initialPosition;

  /// Niveau de zoom initial
  final double initialZoom;

  /// Liste des marqueurs à afficher (au-dessus de tout)
  final List<Marker>? markers;
  
  /// Liste des marqueurs de labels à afficher (sous les marqueurs principaux)
  final List<Marker>? labelMarkers;

  /// Liste des polygones à afficher
  final List<Polygon>? polygons;

  /// Liste des polylines à afficher
  final List<Polyline>? polylines;

  /// Contrôleur de carte externe (optionnel)
  final MapController? mapController;

  /// Callback appelé lorsque la carte est déplacée
  final void Function(MapEvent)? onMapEvent;

  /// Afficher les boutons de contrôle (zoom, localisation)
  final bool showControls;

  /// Style de la carte Mapbox (optionnel)
  /// Si non spécifié, utilise le style par défaut 'mapbox/streets-v12'
  final String? mapStyle;

  /// Désactive le drag de la carte
  final bool disableDrag;

  /// Utiliser OpenStreetMap au lieu de Mapbox (en cas de problème de token)
  @Deprecated('Utiliser tileSource à la place')
  final bool useOpenStreetMap;

  /// Source des tuiles de la carte (Mapbox, OpenStreetMap, IGN Plan, IGN Ortho)
  final TileSource tileSource;

  const MapboxMap({
    super.key,
    this.initialPosition = const LatLng(48.1173, -1.6778), // Rennes par défaut
    this.initialZoom = 13.0,
    this.markers,
    this.labelMarkers,
    this.polygons,
    this.polylines,
    this.mapController,
    this.onMapEvent,
    this.showControls = true,
    this.mapStyle,
    this.disableDrag = false,
    this.useOpenStreetMap = false,
    this.tileSource = TileSource.mapbox,
  });

  @override
  State<MapboxMap> createState() => _MapboxMapState();
}

class _MapboxMapState extends State<MapboxMap> {
  /// Contrôleur de carte interne
  late final MapController _mapController;

  /// Niveau de zoom actuel (utilisé pour l'affichage futur)
  // ignore: unused_field
  double _currentZoom = 13.0;

  /// Provider de tuiles (peut être NetworkTileProvider ou CachedTileProvider)
  TileProvider? _tileProvider;
  
  /// Indique si le cache est initialisé
  bool _cacheInitialized = false;

  @override
  void initState() {
    super.initState();
    _mapController = widget.mapController ?? MapController();
    _currentZoom = widget.initialZoom;
    _initializeCache();
  }

  /// Initialise le cache des tuiles
  Future<void> _initializeCache() async {
    try {
      if (kIsWeb) {
        // Pas de cache sur Web (non supporté)
        setState(() {
          _cacheInitialized = true;
        });
        return;
      }

      final dir = await getTemporaryDirectory();
      final cacheDir = '${dir.path}/map_tiles_cache';

      // Initialiser le HiveCacheStore
      final cacheStore = HiveCacheStore(
        cacheDir,
        hiveBoxName: 'mapTilesCache',
      );

      // Initialiser le CachedTileProvider
      _tileProvider = CachedTileProvider(
        maxStale: const Duration(days: 30),
        store: cacheStore,
      );

      debugPrint('MapboxMap: Cache initialisé dans $cacheDir');

      if (mounted) {
        setState(() {
          _cacheInitialized = true;
        });
      }
      debugPrint('MapboxMap: Cache initialisé avec succès');
    } catch (e) {
      debugPrint('MapboxMap: Erreur lors de l\'initialisation du cache: $e');
      // En cas d'erreur, on continue sans cache
      if (mounted) {
        setState(() {
          _cacheInitialized = true;
          _tileProvider = null; // Utiliser NetworkTileProvider en fallback
        });
      }
    }
  }

  @override
  void dispose() {
    // Ne pas disposer le contrôleur s'il a été fourni de l'extérieur
    if (widget.mapController == null) {
      _mapController.dispose();
    }
    super.dispose();
  }

  /// Construit un bouton de contrôle de carte
  Widget _buildMapButton({
    required IconData icon,
    required VoidCallback onPressed,
  }) {
    return Container(
      width: 40,
      height: 40,
      decoration: BoxDecoration(
        color: Colors.white,
        shape: BoxShape.circle,
        boxShadow: [
          BoxShadow(
            color: Colors.black.withOpacity(0.2),
            blurRadius: 6,
            offset: const Offset(0, 3),
          ),
        ],
      ),
      child: IconButton(
        icon: Icon(icon, size: 20),
        onPressed: onPressed,
        padding: EdgeInsets.zero,
        constraints: const BoxConstraints(),
      ),
    );
  }

  /// Retourne l'URL template pour la source de tuiles sélectionnée
  String _getTileUrlTemplate() {
    // Rétrocompatibilité avec useOpenStreetMap
    // ignore: deprecated_member_use_from_same_package
    if (widget.useOpenStreetMap && widget.tileSource == TileSource.mapbox) {
      return 'https://tile.openstreetmap.org/{z}/{x}/{y}.png';
    }

    switch (widget.tileSource) {
      case TileSource.openStreetMap:
        return 'https://tile.openstreetmap.org/{z}/{x}/{y}.png';

      case TileSource.ignPlan:
        // IGN Plan IGN v2 - Carte routière française
        // Source: https://data.geopf.fr/wmts
        return '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}';

      case TileSource.ignOrtho:
        // IGN Ortho Photos - Photos aériennes
        // Source: https://data.geopf.fr/wmts
        return '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}';

      case TileSource.mapbox:
      default:
        // Déterminer l'URL du template de tuiles Mapbox
        final String environment = ApiService.instance.getCurrentEnvironment();
        final String mapboxToken = AppKeys.getMapboxApiKey(environment);

        if (kIsWeb) {
          return 'https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/256/{z}/{x}/{y}@2x?access_token=$mapboxToken';
        } else {
          return 'https://api.tiles.mapbox.com/v4/mapbox.streets/{z}/{x}/{y}@2x.png?access_token=$mapboxToken';
        }
    }
  }

  /// Retourne le nom de la source de tuiles pour le debug
  String _getTileSourceName() {
    // ignore: deprecated_member_use_from_same_package
    if (widget.useOpenStreetMap && widget.tileSource == TileSource.mapbox) {
      return 'OpenStreetMap (legacy)';
    }
    switch (widget.tileSource) {
      case TileSource.mapbox:
        return 'Mapbox';
      case TileSource.openStreetMap:
        return 'OpenStreetMap';
      case TileSource.ignPlan:
        return 'IGN Plan';
      case TileSource.ignOrtho:
        return 'IGN Ortho Photos';
    }
  }

  @override
  Widget build(BuildContext context) {
    final urlTemplate = _getTileUrlTemplate();
    debugPrint('MapboxMap: Utilisation de ${_getTileSourceName()}');

    // Afficher un indicateur pendant l'initialisation du cache
    if (!_cacheInitialized) {
      return Stack(
        children: [
          // Carte sans cache en attendant
          _buildMapContent(urlTemplate),
          // Indicateur discret
          const Positioned(
            top: 8,
            right: 8,
            child: Card(
              child: Padding(
                padding: EdgeInsets.all(8.0),
                child: Row(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    SizedBox(
                      width: 16,
                      height: 16,
                      child: CircularProgressIndicator(strokeWidth: 2),
                    ),
                    SizedBox(width: 8),
                    Text('Initialisation du cache...', style: TextStyle(fontSize: 12)),
                  ],
                ),
              ),
            ),
          ),
        ],
      );
    }

    return _buildMapContent(urlTemplate);
  }

  Widget _buildMapContent(String urlTemplate) {
    return Stack(
      children: [
        // Carte principale
        FlutterMap(
          mapController: _mapController,
          options: MapOptions(
            initialCenter: widget.initialPosition,
            initialZoom: widget.initialZoom,
            minZoom: 7.0,  // Zoom minimum pour éviter que les tuiles ne se chargent pas
            maxZoom: 20.0, // Zoom maximum
            interactionOptions: InteractionOptions(
              enableMultiFingerGestureRace: true,
              flags: widget.disableDrag
                  ? InteractiveFlag.all & ~InteractiveFlag.drag
                  : InteractiveFlag.all,
            ),
            onMapEvent: (event) {
              if (event is MapEventMove) {
                // Mise à jour du zoom sans rebuild (la variable n'est pas utilisée dans le UI)
                _currentZoom = _mapController.camera.zoom;
              }

              // Appeler le callback externe si fourni
              if (widget.onMapEvent != null) {
                widget.onMapEvent!(event);
              }
            },
          ),
          children: [
            // Tuiles de la carte (Mapbox)
            TileLayer(
              urlTemplate: urlTemplate,
              userAgentPackageName: 'app3.geosector.fr',
              maxNativeZoom: 19,
              maxZoom: 20,
              minZoom: 7,
              // Utiliser le cache sur mobile, NetworkTileProvider sur Web
              tileProvider: !kIsWeb && _cacheInitialized && _tileProvider != null
                  ? _tileProvider!
                  : NetworkTileProvider(
                      headers: {
                        'User-Agent': 'geosector_app/3.3.1',
                        'Accept': '*/*',
                      },
                    ),
              errorTileCallback: (tile, error, stackTrace) {
                // Réduire les logs d'erreur pour ne pas polluer la console
                if (!error.toString().contains('abortTrigger')) {
                  debugPrint('MapboxMap: Erreur de chargement de tuile: $error');
                }
              },
            ),

            // Polygones
            if (widget.polygons != null && widget.polygons!.isNotEmpty) PolygonLayer(polygons: widget.polygons!),
            
            // Marqueurs de labels (sous les marqueurs principaux)
            if (widget.labelMarkers != null && widget.labelMarkers!.isNotEmpty) MarkerLayer(markers: widget.labelMarkers!),

            // Polylines
            if (widget.polylines != null && widget.polylines!.isNotEmpty) PolylineLayer(polylines: widget.polylines!),

            // Marqueurs principaux (au-dessus de tout)
            if (widget.markers != null && widget.markers!.isNotEmpty) MarkerLayer(markers: widget.markers!),
          ],
        ),

        // Boutons de contrôle
        if (widget.showControls)
          Positioned(
            bottom: 16,
            right: 16,
            child: Column(
              children: [
                // Bouton de zoom +
                _buildMapButton(
                  icon: Icons.add,
                  onPressed: () {
                    _mapController.move(
                      _mapController.camera.center,
                      _mapController.camera.zoom + 1,
                    );
                  },
                ),
                const SizedBox(height: 8),

                // Bouton de zoom -
                _buildMapButton(
                  icon: Icons.remove,
                  onPressed: () {
                    _mapController.move(
                      _mapController.camera.center,
                      _mapController.camera.zoom - 1,
                    );
                  },
                ),
                const SizedBox(height: 8),

                // Bouton de localisation
                _buildMapButton(
                  icon: Icons.my_location,
                  onPressed: () {
                    _mapController.move(
                      widget.initialPosition,
                      15,
                    );
                  },
                ),
              ],
            ),
          ),
      ],
    );
  }
}
