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;
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';

/// Widget de graphique d'activité affichant les passages
class ActivityChart extends StatefulWidget {
  /// Liste des données de passage par date et type (si fournie directement)
  /// Format attendu: [{"date": String, "type_passage": int, "nb": int}, ...]
  final List<Map<String, dynamic>>? passageData;

  /// Type de période (Jour, Semaine, Mois, Année)
  final String periodType;

  /// Hauteur du graphique
  final double height;

  /// Nombre de jours à afficher (par défaut 15)
  final int daysToShow;

  /// ID de l'utilisateur pour filtrer les passages (null = tous les utilisateurs)
  final int? userId;

  /// Types de passages à exclure (par défaut [2] = "À finaliser")
  final List<int> excludePassageTypes;

  /// Indique si les données doivent être chargées depuis la Hive box
  final bool loadFromHive;

  /// Callback appelé lorsque la période change
  final Function(int days)? onPeriodChanged;

  /// Titre du graphique
  final String title;

  /// Afficher les étiquettes de valeur
  final bool showDataLabels;

  /// Largeur des colonnes (en pourcentage)
  final double columnWidth;

  /// Espacement entre les colonnes (en pourcentage)
  final double columnSpacing;

  /// Si vrai, n'applique aucun filtrage par utilisateur (affiche tous les passages)
  final bool showAllPassages;

  /// Si vrai, force le rechargement des données
  final bool forceRefresh;

  const ActivityChart({
    super.key,
    this.passageData,
    this.periodType = 'Jour',
    this.height = 350,
    this.daysToShow = 15,
    this.userId,
    this.excludePassageTypes = const [2],
    this.loadFromHive = false,
    this.onPeriodChanged,
    this.title = 'Dernière activité enregistrée sur 15 jours',
    this.showDataLabels = true,
    this.columnWidth = 0.8,
    this.columnSpacing = 0.2,
    this.showAllPassages = false,
    this.forceRefresh = false,
  }) : assert(loadFromHive || passageData != null,
            'Soit loadFromHive doit être true, soit passageData doit être fourni');

  @override
  State<ActivityChart> createState() => _ActivityChartState();
}

/// Classe pour stocker les données d'activité par date
class ActivityData {
  final DateTime date;
  final String dateStr;
  final Map<int, int> passagesByType;
  final int totalPassages;

  ActivityData({
    required this.date,
    required this.dateStr,
    required this.passagesByType,
  }) : totalPassages =
            passagesByType.values.fold(0, (sum, count) => sum + count);
}

class _ActivityChartState extends State<ActivityChart>
    with SingleTickerProviderStateMixin {
  late AnimationController _animationController;

  // Données pour les graphiques
  List<Map<String, dynamic>> _passageData = [];
  List<ActivityData> _chartData = [];
  bool _isLoading = true;
  bool _hasData = false;
  bool _dataLoaded = false;

  // Période sélectionnée en jours
  int _selectedDays = 15;

  // Contrôleur de zoom pour le graphique
  late ZoomPanBehavior _zoomPanBehavior;

  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 1500),
    );

    // Initialiser la période sélectionnée avec la valeur par défaut du widget
    _selectedDays = widget.daysToShow;

    // Initialiser le contrôleur de zoom
    _zoomPanBehavior = ZoomPanBehavior(
      enablePinching: true,
      enableDoubleTapZooming: true,
      enablePanning: true,
      zoomMode: ZoomMode.x,
    );

    _loadData();
    _animationController.forward();
  }

  /// Trouve la date du passage le plus récent
  DateTime _getMostRecentDate() {
    final allDates = [
      ..._passageData.map((data) => DateTime.parse(data['date'] as String)),
    ];
    if (allDates.isEmpty) {
      return DateTime.now();
    }
    return allDates.reduce((a, b) => a.isAfter(b) ? a : b);
  }

  void _loadData() {
    // Marquer comme chargé immédiatement pour éviter les appels multiples pendant le chargement
    // Mais permettre un rechargement ultérieur si nécessaire
    if (_dataLoaded && _hasData) return;

    _dataLoaded = true;

    setState(() {
      _isLoading = true;
    });

    if (widget.loadFromHive) {
      // Charger les données depuis Hive
      WidgetsBinding.instance.addPostFrameCallback((_) {
        // Éviter de recharger si le widget a été démonté entre-temps
        if (!mounted) return;

        try {
          // Utiliser les instances globales définies dans app.dart

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

          // Utiliser le service pour charger les données
          _passageData = passageDataService.loadPassageData(
            daysToShow: _selectedDays,
            excludePassageTypes: widget.excludePassageTypes,
            userId: widget.userId,
            showAllPassages: widget.showAllPassages,
          );

          _prepareChartData();

          // Mettre à jour l'état une seule fois après avoir préparé les données
          if (mounted) {
            setState(() {
              _isLoading = false;
              _hasData = _chartData.isNotEmpty;
            });
          }
        } catch (e) {
          // En cas d'erreur, réinitialiser l'état pour permettre une future tentative
          if (mounted) {
            setState(() {
              _isLoading = false;
              _hasData = false;
            });
          }
        }
      });
    } else {
      // Utiliser les données fournies directement
      _passageData = widget.passageData ?? [];
      _prepareChartData();

      setState(() {
        _isLoading = false;
        _hasData = _chartData.isNotEmpty;
      });
    }
  }

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

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

    // Vérifier si les propriétés importantes ont changé
    final bool periodChanged = oldWidget.periodType != widget.periodType ||
        oldWidget.daysToShow != widget.daysToShow;
    final bool dataSourceChanged = widget.loadFromHive
        ? false
        : oldWidget.passageData != widget.passageData;
    final bool filteringChanged = oldWidget.userId != widget.userId ||
        !listEquals(
            oldWidget.excludePassageTypes, widget.excludePassageTypes) ||
        oldWidget.showAllPassages != widget.showAllPassages;
    final bool refreshForced = widget.forceRefresh && !oldWidget.forceRefresh;

    // Si des paramètres importants ont changé ou si forceRefresh est passé à true, recharger les données
    if (periodChanged ||
        dataSourceChanged ||
        filteringChanged ||
        refreshForced) {
      _selectedDays = widget.daysToShow;
      _dataLoaded = false; // Réinitialiser l'état pour forcer le rechargement
      _loadData();
    }
  }

  // La méthode _loadPassageDataFromHive a été intégrée directement dans _loadData
  // pour éviter les appels multiples et les problèmes de cycle de vie

  /// Prépare les données pour le graphique
  void _prepareChartData() {
    try {
      // Vérifier que les données sont disponibles
      if (_passageData.isEmpty) {
        _chartData = [];
        return;
      }

      // Obtenir toutes les dates uniques
      final Set<String> uniqueDatesSet = {};
      for (final data in _passageData) {
        if (data.containsKey('date') && data['date'] != null) {
          uniqueDatesSet.add(data['date'] as String);
        }
      }

      // Trier les dates
      final List<String> uniqueDates = uniqueDatesSet.toList();
      uniqueDates.sort();

      // Créer les données pour chaque date
      _chartData = [];
      for (final dateStr in uniqueDates) {
        final passagesByType = <int, int>{};

        // Initialiser tous les types de passage possibles
        for (final typeId in AppKeys.typesPassages.keys) {
          if (!widget.excludePassageTypes.contains(typeId)) {
            passagesByType[typeId] = 0;
          }
        }

        // Remplir les données de passage
        for (final data in _passageData) {
          if (data.containsKey('date') &&
              data['date'] == dateStr &&
              data.containsKey('type_passage') &&
              data.containsKey('nb')) {
            final typeId = data['type_passage'] as int;
            if (!widget.excludePassageTypes.contains(typeId)) {
              passagesByType[typeId] = data['nb'] as int;
            }
          }
        }

        try {
          // Convertir la date en objet DateTime
          final dateParts = dateStr.split('-');
          if (dateParts.length == 3) {
            final year = int.parse(dateParts[0]);
            final month = int.parse(dateParts[1]);
            final day = int.parse(dateParts[2]);

            final date = DateTime(year, month, day);

            // Ajouter les données à la liste
            _chartData.add(ActivityData(
              date: date,
              dateStr: dateStr,
              passagesByType: passagesByType,
            ));
          }
        } catch (e) {
          // Silencieux lors des erreurs de conversion de date pour éviter les logs excessifs
        }
      }

      // Trier les données par date
      _chartData.sort((a, b) => a.date.compareTo(b.date));
    } catch (e) {
      // Erreur silencieuse pour éviter les logs excessifs
      _chartData = [];
    }
  }

  @override
  Widget build(BuildContext context) {
    if (_isLoading) {
      return SizedBox(
        height: widget.height,
        child: const Center(
          child: CircularProgressIndicator(),
        ),
      );
    }

    if (!_hasData || _chartData.isEmpty) {
      return SizedBox(
        height: widget.height,
        child: const Center(
          child: Text('Aucune donnée disponible'),
        ),
      );
    }

    // Préparer les données si nécessaire
    if (_chartData.isEmpty) {
      _prepareChartData();
    }

    return SizedBox(
      height: widget.height,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // Titre (conservé)
          if (widget.title.isNotEmpty)
            Padding(
              padding: const EdgeInsets.only(
                  left: 16.0, right: 16.0, top: 16.0, bottom: 8.0),
              child: Text(
                widget.title,
                style: Theme.of(context).textTheme.titleMedium?.copyWith(
                      fontWeight: FontWeight.bold,
                    ),
              ),
            ),
          // Graphique (occupe maintenant plus d'espace)
          Expanded(
            child: Padding(
              padding: const EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 16.0),
              child: SfCartesianChart(
                plotAreaBorderWidth: 0,
                legend: Legend(
                  isVisible: true,
                  position: LegendPosition.bottom,
                  overflowMode: LegendItemOverflowMode.wrap,
                ),
                primaryXAxis: DateTimeAxis(
                  dateFormat: DateFormat('dd/MM'),
                  intervalType: DateTimeIntervalType.days,
                  majorGridLines: const MajorGridLines(width: 0),
                  labelStyle: const TextStyle(fontSize: 10),
                  // Définir explicitement la plage de dates à afficher
                  minimum: _chartData.isNotEmpty ? _chartData.first.date : null,
                  maximum: _chartData.isNotEmpty ? _chartData.last.date : null,
                  // Assurer que tous les jours sont affichés
                  interval: 1,
                  axisLabelFormatter: (AxisLabelRenderDetails details) {
                    return ChartAxisLabel(details.text, details.textStyle);
                  },
                ),
                primaryYAxis: NumericAxis(
                  labelStyle: const TextStyle(fontSize: 10),
                  axisLine: const AxisLine(width: 0),
                  majorTickLines: const MajorTickLines(size: 0),
                  majorGridLines: const MajorGridLines(
                    width: 0.5,
                    color: Colors.grey,
                    dashArray: <double>[5, 5], // Motif de pointillés
                  ),
                  title: const AxisTitle(
                    text: 'Passages',
                    textStyle: TextStyle(fontSize: 10, color: Colors.grey),
                  ),
                ),
                series: _buildSeries(),
                tooltipBehavior: TooltipBehavior(enable: true),
                zoomPanBehavior: _zoomPanBehavior,
              ),
            ),
          ),
        ],
      ),
    );
  }

  /// Construit les séries de données pour le graphique
  List<CartesianSeries<ActivityData, DateTime>> _buildSeries() {
    final List<CartesianSeries<ActivityData, DateTime>> series = [];

    // Vérifier que les données sont disponibles
    if (_chartData.isEmpty) {
      return series;
    }

    // Obtenir tous les types de passage (sauf ceux exclus)
    final passageTypes = AppKeys.typesPassages.keys
        .where((typeId) => !widget.excludePassageTypes.contains(typeId))
        .toList();

    // Créer les séries pour les passages (colonnes empilées)
    for (final typeId in passageTypes) {
      // Vérifier que le type existe dans AppKeys
      if (!AppKeys.typesPassages.containsKey(typeId)) {
        continue;
      }
      final typeInfo = AppKeys.typesPassages[typeId]!;

      // Vérifier que les clés nécessaires existent
      if (!typeInfo.containsKey('couleur1') || !typeInfo.containsKey('titre')) {
        continue;
      }

      final typeColor = Color(typeInfo['couleur1'] as int);
      final typeName = typeInfo['titre'] as String;

      // Calculer le total pour ce type pour déterminer s'il faut l'afficher
      int totalForType = 0;
      for (final data in _chartData) {
        totalForType += data.passagesByType[typeId] ?? 0;
      }

      // On peut décider de ne pas afficher les types sans données
      final addZeroValueTypes = false;

      // Ajouter la série pour ce type
      if (totalForType > 0 || addZeroValueTypes) {
        series.add(
          StackedColumnSeries<ActivityData, DateTime>(
            name: typeName,
            dataSource: _chartData,
            xValueMapper: (ActivityData data, _) => data.date,
            yValueMapper: (ActivityData data, _) {
              final value = data.passagesByType.containsKey(typeId)
                  ? data.passagesByType[typeId]!
                  : 0;
              return value;
            },
            color: typeColor,
            width: widget.columnWidth,
            spacing: widget.columnSpacing,
            dataLabelSettings: DataLabelSettings(
              isVisible: widget.showDataLabels,
              labelAlignment: ChartDataLabelAlignment.middle,
              textStyle: const TextStyle(fontSize: 8, color: Colors.white),
            ),
            markerSettings: const MarkerSettings(isVisible: false),
            animationDuration: 1500,
          ),
        );
      }
    }

    return series;
  }
}
