import 'package:geosector_app/app.dart'; // Pour accéder aux instances globales
import 'package:flutter/material.dart';
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:hive_flutter/hive_flutter.dart';
import 'package:geosector_app/core/data/models/passage_model.dart';
import 'package:geosector_app/core/services/current_user_service.dart';
import 'package:go_router/go_router.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}, ...]
  /// Si useValueListenable est true, ce paramètre est ignoré
  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;

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

  /// Utiliser ValueListenableBuilder pour la mise à jour automatique
  final bool useValueListenable;

  /// Afficher les boutons de sélection de période (7j, 14j, 21j)
  final bool showPeriodButtons;

  const ActivityChart({
    super.key,
    this.passageData,
    this.periodType = 'Jour',
    this.height = 350,
    this.daysToShow = 15,
    this.userId,
    this.excludePassageTypes = const [2],
    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.useValueListenable = true,
    this.showPeriodButtons = false,
  });

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

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

  // Période sélectionnée pour le filtre (7, 14 ou 21 jours)
  late int _selectedDays;

  @override
  void initState() {
    super.initState();
    _selectedDays = widget.daysToShow;

    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 1500),
    );

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

    _animationController.forward();
  }

  @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.useValueListenable
        ? false
        : oldWidget.passageData != widget.passageData;
    final bool filteringChanged = oldWidget.userId != widget.userId ||
        !listEquals(
            oldWidget.excludePassageTypes, widget.excludePassageTypes) ||
        oldWidget.showAllPassages != widget.showAllPassages ||
        oldWidget.useValueListenable != widget.useValueListenable;

    // Si des paramètres importants ont changé, relancer l'animation
    if (periodChanged || dataSourceChanged || filteringChanged) {
      _animationController.reset();
      _animationController.forward();
    }
  }

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

  @override
  Widget build(BuildContext context) {
    if (widget.useValueListenable) {
      return _buildWithValueListenable();
    } else {
      return _buildWithStaticData();
    }
  }

  /// Construction du widget avec ValueListenableBuilder pour mise à jour automatique
  Widget _buildWithValueListenable() {
    return ValueListenableBuilder(
      valueListenable:
          Hive.box<PassageModel>(AppKeys.passagesBoxName).listenable(),
      builder: (context, Box<PassageModel> passagesBox, child) {
        final chartData = _calculateActivityData(passagesBox, _selectedDays);
        return _buildChart(chartData);
      },
    );
  }

  /// Construction du widget avec des données statiques
  Widget _buildWithStaticData() {
    if (widget.passageData == null) {
      return SizedBox(
        height: widget.height,
        child: const Center(
          child: Text('Aucune donnée fournie'),
        ),
      );
    }

    final chartData = _prepareChartDataFromPassageData(widget.passageData!);
    return _buildChart(chartData);
  }

  /// Calcule les données d'activité depuis la Hive box
  List<ActivityData> _calculateActivityData(
      Box<PassageModel> passagesBox, int daysToShow) {
    try {
      final passages = passagesBox.values.toList();
      final currentUser = userRepository.getCurrentUser();

      // Pour les users : récupérer les secteurs assignés
      Set<int>? userSectorIds;
      if (!widget.showAllPassages && currentUser != null) {
        final userSectors = userRepository.getUserSectors();
        userSectorIds = userSectors.map((sector) => sector.id).toSet();
        debugPrint(
            'ActivityChart: Mode USER - Secteurs assignés: $userSectorIds');
      } else {
        debugPrint('ActivityChart: Mode ADMIN - Tous les passages');
      }

      // Calculer la date de début (nombre de jours en arrière)
      final endDate = DateTime.now();
      final startDate = endDate.subtract(Duration(days: daysToShow - 1));

      debugPrint(
          'ActivityChart: Période du ${DateFormat('yyyy-MM-dd').format(startDate)} au ${DateFormat('yyyy-MM-dd').format(endDate)}');
      debugPrint('ActivityChart: Nombre total de passages: ${passages.length}');

      // Préparer les données par date
      final Map<String, Map<int, int>> dataByDate = {};

      // Initialiser toutes les dates de la période
      for (int i = 0; i < daysToShow; i++) {
        final date = startDate.add(Duration(days: i));
        final dateStr = DateFormat('yyyy-MM-dd').format(date);
        dataByDate[dateStr] = {};

        // Initialiser tous les types de passage possibles
        for (final typeId in AppKeys.typesPassages.keys) {
          dataByDate[dateStr]![typeId] = 0;
        }
      }

      // Parcourir les passages et les compter par date et type
      int includedCount = 0;
      for (final passage in passages) {
        // Appliquer les filtres
        bool shouldInclude = true;

        // Filtrer par secteurs assignés si nécessaire (pour les users)
        if (userSectorIds != null &&
            !userSectorIds.contains(passage.fkSector)) {
          shouldInclude = false;
        }

        // Exclure les passages de type 2 (À finaliser) avec nbPassages = 0
        if (shouldInclude && passage.fkType == 2 && passage.nbPassages == 0) {
          shouldInclude = false;
        }

        // Vérifier si le passage est dans la période
        final passageDate = passage.passedAt;
        if (shouldInclude &&
            (passageDate == null ||
                passageDate.isBefore(startDate) ||
                passageDate.isAfter(endDate))) {
          shouldInclude = false;
        }

        if (shouldInclude && passageDate != null) {
          final dateStr = DateFormat('yyyy-MM-dd').format(passageDate);
          if (dataByDate.containsKey(dateStr)) {
            dataByDate[dateStr]![passage.fkType] =
                (dataByDate[dateStr]![passage.fkType] ?? 0) + 1;
            includedCount++;
          }
        }
        // Debug désactivé pour éviter la pollution de la console avec les passages type 2 sans date
        // else if (!shouldInclude && userSectorIds != null) {
        //   debugPrint(
        //       'ActivityChart: Passage #${passage.id} exclu - $excludeReason (type=${passage.fkType}, secteur=${passage.fkSector}, date=${passageDate != null ? DateFormat('yyyy-MM-dd').format(passageDate) : 'null'})');
        // }
      }

      debugPrint(
          'ActivityChart: Passages inclus dans le graphique: $includedCount');

      // Convertir en liste d'ActivityData
      final List<ActivityData> chartData = [];
      dataByDate.forEach((dateStr, passagesByType) {
        final dateParts = dateStr.split('-');
        if (dateParts.length == 3) {
          try {
            final date = DateTime(
              int.parse(dateParts[0]),
              int.parse(dateParts[1]),
              int.parse(dateParts[2]),
            );

            chartData.add(ActivityData(
              date: date,
              dateStr: dateStr,
              passagesByType: passagesByType,
            ));
          } catch (e) {
            debugPrint('Erreur de conversion de date: $dateStr');
          }
        }
      });

      // Trier par date
      chartData.sort((a, b) => a.date.compareTo(b.date));
      return chartData;
    } catch (e) {
      debugPrint('Erreur lors du calcul des données d\'activité: $e');
      return [];
    }
  }

  /// Prépare les données pour le graphique à partir des données de passage brutes (ancien système)
  List<ActivityData> _prepareChartDataFromPassageData(
      List<Map<String, dynamic>> passageData) {
    try {
      // 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
      final List<ActivityData> 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) {
          debugPrint('Erreur de conversion de date: $dateStr');
        }
      }

      // Trier les données par date
      chartData.sort((a, b) => a.date.compareTo(b.date));
      return chartData;
    } catch (e) {
      debugPrint('Erreur lors de la préparation des données: $e');
      return [];
    }
  }

  /// Construit le graphique avec les données fournies
  Widget _buildChart(List<ActivityData> chartData) {
    if (chartData.isEmpty) {
      return SizedBox(
        height: widget.height,
        child: const Center(
          child: Text('Aucune donnée disponible'),
        ),
      );
    }

    return SizedBox(
      height: widget.height,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // En-tête avec titre et boutons de filtre
          if (widget.title.isNotEmpty)
            Padding(
              padding: const EdgeInsets.only(
                  left: 16.0, right: 16.0, top: 16.0, bottom: 8.0),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Text(
                    widget.title,
                    style: Theme.of(context).textTheme.titleMedium?.copyWith(
                          fontWeight: FontWeight.bold,
                        ),
                  ),
                  if (widget.showPeriodButtons)
                    Row(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        _buildPeriodButton(7),
                        const SizedBox(width: 4),
                        _buildPeriodButton(14),
                        const SizedBox(width: 4),
                        _buildPeriodButton(21),
                      ],
                    ),
                ],
              ),
            ),
          // Graphique
          Expanded(
            child: Padding(
              padding: const EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 16.0),
              child: SfCartesianChart(
                plotAreaBorderWidth: 0,
                legend: const 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),
                  minimum: chartData.isNotEmpty ? chartData.first.date : null,
                  maximum: chartData.isNotEmpty ? chartData.last.date : null,
                  interval: 1,
                ),
                primaryYAxis: const NumericAxis(
                  labelStyle: TextStyle(fontSize: 10),
                  axisLine: AxisLine(width: 0),
                  majorTickLines: MajorTickLines(size: 0),
                  majorGridLines: MajorGridLines(
                    width: 0.5,
                    color: Colors.grey,
                    dashArray: <double>[5, 5],
                  ),
                  title: AxisTitle(
                    text: 'Passages',
                    textStyle: TextStyle(fontSize: 10, color: Colors.grey),
                  ),
                ),
                series: _buildSeries(chartData),
                tooltipBehavior: TooltipBehavior(enable: true),
                zoomPanBehavior: _zoomPanBehavior,
              ),
            ),
          ),
        ],
      ),
    );
  }

  /// Construit les séries de données pour le graphique
  List<CartesianSeries<ActivityData, DateTime>> _buildSeries(
      List<ActivityData> chartData) {
    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
    final passageTypes = AppKeys.typesPassages.keys.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;
      }

      // Ajouter la série pour ce type si elle a des données
      if (totalForType > 0) {
        series.add(
          StackedColumnSeries<ActivityData, DateTime>(
            name: typeName,
            dataSource: chartData,
            xValueMapper: (ActivityData data, _) => data.date,
            yValueMapper: (ActivityData data, _) {
              return data.passagesByType[typeId] ?? 0;
            },
            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,
            // Ajouter le callback de clic uniquement depuis home_page
            onPointTap: widget.showPeriodButtons
                ? (ChartPointDetails details) {
                    _handlePointTap(details, typeId);
                  }
                : null,
          ),
        );
      }
    }

    return series;
  }

  /// Gère le clic sur un point du graphique
  void _handlePointTap(ChartPointDetails details, int typeId) {
    if (details.pointIndex == null || details.pointIndex! < 0) return;

    // Récupérer les données du point cliqué
    final passageBox = Hive.box<PassageModel>(AppKeys.passagesBoxName);

    // Créer les données d'activité
    final chartData = _calculateActivityData(passageBox, _selectedDays);

    if (details.pointIndex! >= chartData.length) return;

    final clickedData = chartData[details.pointIndex!];
    final clickedDate = clickedData.date;

    // Réinitialiser tous les filtres sauf celui sélectionné
    final settingsBox = Hive.box(AppKeys.settingsBoxName);
    settingsBox.delete('history_selectedPaymentTypeId');
    settingsBox.delete('history_selectedSectorId');
    settingsBox.delete('history_selectedSectorName');
    settingsBox.delete('history_selectedMemberId');

    // Sauvegarder le type de passage et les dates (début et fin de journée)
    settingsBox.put('history_selectedTypeId', typeId);

    // Date de début : début de la journée cliquée
    final startDateTime =
        DateTime(clickedDate.year, clickedDate.month, clickedDate.day, 0, 0, 0);
    settingsBox.put('history_startDate', startDateTime.millisecondsSinceEpoch);

    // Date de fin : fin de la journée cliquée
    final endDateTime = DateTime(
        clickedDate.year, clickedDate.month, clickedDate.day, 23, 59, 59);
    settingsBox.put('history_endDate', endDateTime.millisecondsSinceEpoch);

    // Naviguer vers la page historique
    final bool isAdmin = CurrentUserService.instance.shouldShowAdminUI;
    context.go(isAdmin ? '/admin/history' : '/user/history');
  }

  /// Construit un bouton de sélection de période
  Widget _buildPeriodButton(int days) {
    final isSelected = _selectedDays == days;
    return InkWell(
      onTap: () {
        setState(() {
          _selectedDays = days;
          _animationController.reset();
          _animationController.forward();
        });
        widget.onPeriodChanged?.call(days);
      },
      borderRadius: BorderRadius.circular(4),
      child: Container(
        padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
        decoration: BoxDecoration(
          color: isSelected
              ? Theme.of(context).colorScheme.primary
              : Colors.grey.withOpacity(0.1),
          borderRadius: BorderRadius.circular(4),
          border: Border.all(
            color: isSelected
                ? Theme.of(context).colorScheme.primary
                : Colors.grey.shade400,
            width: 1,
          ),
        ),
        child: Text(
          '${days}j',
          style: TextStyle(
            fontSize: 12,
            fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
            color: isSelected ? Colors.white : Colors.grey.shade700,
          ),
        ),
      ),
    );
  }
}
