import 'package:geosector_app/app.dart'; // Pour accéder aux instances globales
import 'package:flutter/material.dart';
import 'package:geosector_app/app.dart'; // Pour accéder aux instances globales
import 'package:flutter/foundation.dart' show listEquals, mapEquals;
import 'package:intl/intl.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:geosector_app/core/constants/app_keys.dart';
import 'package:geosector_app/core/repositories/passage_repository.dart';
import 'package:geosector_app/core/repositories/user_repository.dart';
import 'package:geosector_app/core/services/passage_data_service.dart';

/// Modèle de données pour le graphique en camembert des passages
class PassageChartData {
  /// Identifiant du type de passage
  final int typeId;

  /// Nombre de passages de ce type
  final int count;

  /// Titre du type de passage
  final String title;

  /// Couleur associée au type de passage
  final Color color;

  /// Icône associée au type de passage
  final IconData icon;

  PassageChartData({
    required this.typeId,
    required this.count,
    required this.title,
    required this.color,
    required this.icon,
  });
}

/// Widget de graphique en camembert pour représenter la répartition des passages par type
class PassagePieChart extends StatefulWidget {
  /// Liste des données de passages par type sous forme de Map avec typeId et count
  /// Si loadFromHive est true, ce paramètre est ignoré
  final Map<int, int> passagesByType;

  /// Taille du graphique
  final double size;

  /// Taille des étiquettes
  final double labelSize;

  /// Afficher les pourcentages
  final bool showPercentage;

  /// Afficher les icônes
  final bool showIcons;

  /// Afficher la légende
  final bool showLegend;

  /// Format donut (anneau)
  final bool isDonut;

  /// Rayon central pour le format donut (en pourcentage)
  final String innerRadius;

  /// Charger les données depuis Hive
  final bool loadFromHive;

  /// ID de l'utilisateur pour filtrer les passages (utilisé seulement si loadFromHive est true)
  final int? userId;

  /// Types de passages à exclure (utilisé seulement si loadFromHive est true)
  final List<int> excludePassageTypes;

  /// Afficher tous les passages sans filtrer par utilisateur (utilisé seulement si loadFromHive est true)
  final bool showAllPassages;

  const PassagePieChart({
    super.key,
    this.passagesByType = const {},
    this.size = 300,
    this.labelSize = 12,
    this.showPercentage = true,
    this.showIcons = true,
    this.showLegend = true,
    this.isDonut = false,
    this.innerRadius = '40%',
    this.loadFromHive = false,
    this.userId,
    this.excludePassageTypes = const [2],
    this.showAllPassages = false,
  });

  @override
  State<PassagePieChart> createState() => _PassagePieChartState();
}

class _PassagePieChartState extends State<PassagePieChart>
    with SingleTickerProviderStateMixin {
  late AnimationController _animationController;

  /// Données de passages par type
  late Map<int, int> _passagesByType;

  /// Variables pour la mise en cache et l'optimisation
  bool _dataLoaded = false;
  bool _isLoading = false;
  List<PassageChartData>? _cachedChartData;
  List<CircularChartAnnotation>? _cachedAnnotations;

  @override
  void initState() {
    super.initState();
    _passagesByType = widget.passagesByType;

    // Initialiser le contrôleur d'animation
    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 2000),
    );

    _animationController.forward();

    // Si nous n'utilisons pas Hive, préparer les données immédiatement
    if (!widget.loadFromHive) {
      _prepareChartData();
    }
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    if (widget.loadFromHive && !_dataLoaded && !_isLoading) {
      _isLoading = true; // Prévenir les chargements multiples
      _loadPassageDataFromHive(context);
    }
  }

  @override
  void didUpdateWidget(PassagePieChart oldWidget) {
    super.didUpdateWidget(oldWidget);

    // Vérifier si les propriétés importantes ont changé
    final bool dataSourceChanged = widget.loadFromHive
        ? false
        : !mapEquals(oldWidget.passagesByType, widget.passagesByType);
    final bool filteringChanged = oldWidget.userId != widget.userId ||
        !listEquals(
            oldWidget.excludePassageTypes, widget.excludePassageTypes) ||
        oldWidget.showAllPassages != widget.showAllPassages;
    final bool visualChanged = oldWidget.size != widget.size ||
        oldWidget.labelSize != widget.labelSize ||
        oldWidget.showPercentage != widget.showPercentage ||
        oldWidget.showIcons != widget.showIcons ||
        oldWidget.showLegend != widget.showLegend ||
        oldWidget.isDonut != widget.isDonut ||
        oldWidget.innerRadius != widget.innerRadius;

    // Si les paramètres de filtrage ou de source de données ont changé, recharger les données
    if (dataSourceChanged || filteringChanged) {
      _cachedChartData = null;
      _cachedAnnotations = null;

      // Relancer l'animation si les données ont changé
      _animationController.reset();
      _animationController.forward();

      if (!widget.loadFromHive) {
        _passagesByType = widget.passagesByType;
        _prepareChartData();
      } else if (!_isLoading) {
        _dataLoaded = false;
        _isLoading = true;
        _loadPassageDataFromHive(context);
      }
    }
    // Si seuls les paramètres visuels ont changé, recalculer les annotations sans recharger les données
    else if (visualChanged) {
      _cachedAnnotations = null;
    }
  }

  /// Charge les données de passage depuis Hive en utilisant le service PassageDataService
  void _loadPassageDataFromHive(BuildContext context) {
    // Éviter les appels multiples pendant le chargement
    if (_isLoading) {
      debugPrint('PassagePieChart: Déjà en cours de chargement, ignoré');
      return;
    }

    // Si les données sont déjà chargées et non vides, ne pas recharger
    if (_dataLoaded && _passagesByType.isNotEmpty) {
      debugPrint('PassagePieChart: Données déjà chargées, ignoré');
      return;
    }

    debugPrint('PassagePieChart: Début du chargement des données');
    setState(() {
      _isLoading = true;
    });

    // Charger les données dans un addPostFrameCallback pour éviter les problèmes de cycle de vie
    WidgetsBinding.instance.addPostFrameCallback((_) {
      // Vérifier si le widget est toujours monté
      if (!mounted) {
        debugPrint('PassagePieChart: Widget démonté, chargement annulé');
        return;
      }

      try {
        debugPrint('PassagePieChart: Création du service de données');
        // Utiliser les instances globales définies dans app.dart

        // Vérifier que les repositories sont disponibles
        if (passageRepository == null) {
          debugPrint('PassagePieChart: ERREUR - passageRepository est null');
          if (mounted) {
            setState(() {
              _isLoading = false;
            });
          }
          return;
        }

        if (userRepository == null) {
          debugPrint('PassagePieChart: ERREUR - userRepository est null');
          if (mounted) {
            setState(() {
              _isLoading = false;
            });
          }
          return;
        }

        // Créer une instance du service de données
        final passageDataService = PassageDataService(
          passageRepository: passageRepository,
          userRepository: userRepository,
        );

        debugPrint(
            'PassagePieChart: Chargement des données avec excludePassageTypes=${widget.excludePassageTypes}, userId=${widget.userId}, showAllPassages=${widget.showAllPassages}');

        // Utiliser le service pour charger les données
        final data = passageDataService.loadPassageDataForPieChart(
          excludePassageTypes: widget.excludePassageTypes,
          userId: widget.userId,
          showAllPassages: widget.showAllPassages,
        );

        debugPrint('PassagePieChart: Données chargées: $data');

        // Mettre à jour les données et les états
        if (mounted) {
          setState(() {
            _passagesByType = data;
            _dataLoaded = true;
            _isLoading = false;
            _cachedChartData =
                null; // Forcer la régénération des données du graphique
            _cachedAnnotations = null;
          });

          // Préparer les données du graphique
          _prepareChartData();
          debugPrint('PassagePieChart: Données préparées pour le graphique');
        }
      } catch (e) {
        // Gérer les erreurs et réinitialiser l'état pour permettre une future tentative
        debugPrint(
            'PassagePieChart: ERREUR lors du chargement des données: $e');
        if (mounted) {
          setState(() {
            _isLoading = false;
          });
        }
      }
    });
  }

  /// Prépare les données pour le graphique en camembert avec mise en cache
  List<PassageChartData> _prepareChartData() {
    // Utiliser les données en cache si disponibles
    if (_cachedChartData != null) {
      debugPrint('PassagePieChart: Utilisation des données en cache');
      return _cachedChartData!;
    }

    debugPrint('PassagePieChart: Préparation des données pour le graphique');
    debugPrint('PassagePieChart: Données brutes: $_passagesByType');

    // Vérifier si les données sont vides
    if (_passagesByType.isEmpty) {
      debugPrint('PassagePieChart: Aucune donnée disponible');
      return [];
    }

    // Vérifier si les données contiennent uniquement des passages de type 2
    bool onlyType2 = true;
    _passagesByType.forEach((typeId, count) {
      if (typeId != 2 && count > 0) {
        onlyType2 = false;
      }
    });

    if (onlyType2) {
      debugPrint(
          'PassagePieChart: Les données contiennent uniquement des passages de type 2');
    }

    final List<PassageChartData> chartData = [];

    // Créer les données du graphique
    _passagesByType.forEach((typeId, count) {
      // Vérifier que le type existe et que le compteur est positif
      if (count > 0 && AppKeys.typesPassages.containsKey(typeId)) {
        // Vérifier si le type est exclu
        bool isExcluded = widget.excludePassageTypes.contains(typeId);
        if (isExcluded) {
          debugPrint('PassagePieChart: Type $typeId exclu');
        } else {
          final typeInfo = AppKeys.typesPassages[typeId]!;
          final typeName = typeInfo['titre'] as String;
          debugPrint(
              'PassagePieChart: Ajout du type $typeId ($typeName) avec $count passages');

          chartData.add(PassageChartData(
            typeId: typeId,
            count: count,
            title: typeName,
            color: Color(typeInfo['couleur2'] as int),
            icon: typeInfo['icon_data'] as IconData,
          ));
        }
      } else {
        if (count <= 0) {
          debugPrint('PassagePieChart: Type $typeId ignoré car count=$count');
        } else if (!AppKeys.typesPassages.containsKey(typeId)) {
          debugPrint(
              'PassagePieChart: Type $typeId ignoré car non défini dans AppKeys.typesPassages');
        }
      }
    });

    debugPrint(
        'PassagePieChart: ${chartData.length} types de passages ajoutés au graphique');

    // Mettre en cache les données générées
    _cachedChartData = chartData;

    return chartData;
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // Si les données doivent être chargées depuis Hive mais ne sont pas encore prêtes
    if (widget.loadFromHive && !_dataLoaded) {
      return SizedBox(
        width: widget.size,
        height: widget.size,
        child: const Center(
          child: CircularProgressIndicator(),
        ),
      );
    }

    final chartData = _prepareChartData();

    // Si aucune donnée, afficher un message
    if (chartData.isEmpty) {
      return SizedBox(
        width: widget.size,
        height: widget.size,
        child: const Center(
          child: Text('Aucune donnée disponible'),
        ),
      );
    }

    // Créer des animations pour différents aspects du graphique
    final progressAnimation = CurvedAnimation(
      parent: _animationController,
      curve: Curves.easeOutCubic,
    );

    final explodeAnimation = CurvedAnimation(
      parent: _animationController,
      curve: Interval(0.7, 1.0, curve: Curves.elasticOut),
    );

    final opacityAnimation = CurvedAnimation(
      parent: _animationController,
      curve: Interval(0.1, 0.5, curve: Curves.easeIn),
    );

    return AnimatedBuilder(
      animation: _animationController,
      builder: (context, child) {
        return SizedBox(
          width: widget.size,
          height: widget.size,
          child: SfCircularChart(
            margin: EdgeInsets.zero,
            legend: Legend(
              isVisible: widget.showLegend,
              position: LegendPosition.bottom,
              overflowMode: LegendItemOverflowMode.wrap,
              textStyle: TextStyle(fontSize: widget.labelSize),
            ),
            tooltipBehavior: TooltipBehavior(enable: true),
            series: <CircularSeries>[
              widget.isDonut
                  ? DoughnutSeries<PassageChartData, String>(
                      dataSource: chartData,
                      xValueMapper: (PassageChartData data, _) => data.title,
                      yValueMapper: (PassageChartData data, _) => data.count,
                      pointColorMapper: (PassageChartData data, _) =>
                          data.color,
                      enableTooltip: true,
                      dataLabelMapper: (PassageChartData data, _) {
                        if (widget.showPercentage) {
                          // Calculer le pourcentage avec une décimale
                          final total = chartData.fold(
                              0, (sum, item) => sum + item.count);
                          final percentage = (data.count / total * 100);
                          return '${percentage.toStringAsFixed(1)}%';
                        } else {
                          return data.title;
                        }
                      },
                      dataLabelSettings: DataLabelSettings(
                        isVisible: true,
                        labelPosition: ChartDataLabelPosition.outside,
                        textStyle: TextStyle(fontSize: widget.labelSize),
                        connectorLineSettings: const ConnectorLineSettings(
                          type: ConnectorType.curve,
                          length: '15%',
                        ),
                      ),
                      innerRadius: widget.innerRadius,
                      explode: true,
                      explodeIndex: 0,
                      explodeOffset:
                          '${(5 * explodeAnimation.value).toStringAsFixed(1)}%',
                      opacity: opacityAnimation.value,
                      animationDuration:
                          0, // On désactive l'animation intégrée car nous utilisons notre propre animation
                      startAngle: 270,
                      endAngle: 270 + (360 * progressAnimation.value).toInt(),
                    )
                  : PieSeries<PassageChartData, String>(
                      dataSource: chartData,
                      xValueMapper: (PassageChartData data, _) => data.title,
                      yValueMapper: (PassageChartData data, _) => data.count,
                      pointColorMapper: (PassageChartData data, _) =>
                          data.color,
                      enableTooltip: true,
                      dataLabelMapper: (PassageChartData data, _) {
                        if (widget.showPercentage) {
                          // Calculer le pourcentage avec une décimale
                          final total = chartData.fold(
                              0, (sum, item) => sum + item.count);
                          final percentage = (data.count / total * 100);
                          return '${percentage.toStringAsFixed(1)}%';
                        } else {
                          return data.title;
                        }
                      },
                      dataLabelSettings: DataLabelSettings(
                        isVisible: true,
                        labelPosition: ChartDataLabelPosition.outside,
                        textStyle: TextStyle(fontSize: widget.labelSize),
                        connectorLineSettings: const ConnectorLineSettings(
                          type: ConnectorType.curve,
                          length: '15%',
                        ),
                      ),
                      explode: true,
                      explodeIndex: 0,
                      explodeOffset:
                          '${(5 * explodeAnimation.value).toStringAsFixed(1)}%',
                      opacity: opacityAnimation.value,
                      animationDuration:
                          0, // On désactive l'animation intégrée car nous utilisons notre propre animation
                      startAngle: 270,
                      endAngle: 270 + (360 * progressAnimation.value).toInt(),
                    ),
            ],
            annotations:
                widget.showIcons ? _buildIconAnnotations(chartData) : null,
          ),
        );
      },
    );
  }

  /// Crée les annotations d'icônes pour le graphique avec mise en cache
  List<CircularChartAnnotation> _buildIconAnnotations(
      List<PassageChartData> chartData) {
    // Utiliser les annotations en cache si disponibles
    if (_cachedAnnotations != null) {
      return _cachedAnnotations!;
    }

    final List<CircularChartAnnotation> annotations = [];

    // Calculer le total pour les pourcentages
    int total = chartData.fold(0, (sum, item) => sum + item.count);
    if (total == 0) return []; // Éviter la division par zéro

    // Position angulaire actuelle (en radians)
    double currentAngle = 0;

    for (int i = 0; i < chartData.length; i++) {
      final data = chartData[i];
      final percentage = data.count / total;

      // Calculer l'angle central de ce segment
      final segmentAngle = percentage * 2 * 3.14159;
      final midAngle = currentAngle + (segmentAngle / 2);

      // Ajouter une annotation pour l'icône
      annotations.add(
        CircularChartAnnotation(
          widget: Icon(
            data.icon,
            color: Colors.white,
            size: 16,
          ),
          radius: '50%',
          angle: (midAngle * (180 / 3.14159)).toInt(), // Convertir en degrés
        ),
      );

      // Mettre à jour l'angle actuel
      currentAngle += segmentAngle;
    }

    // Mettre en cache les annotations générées
    _cachedAnnotations = annotations;

    return annotations;
  }
}
