// SPDX-FileCopyrightText: © 2025 Nøkken.io <nokken.io@proton.me>
// SPDX-License-Identifier: AGPL-3.0
//
// monthly_trends_card.dart
//
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:intl/intl.dart';
import 'package:nokken/src/core/ui/theme/app_colors.dart';
import 'package:nokken/src/core/ui/theme/app_text_styles.dart';
import 'package:nokken/src/core/ui/theme/app_theme.dart';
import 'package:nokken/src/core/ui/widgets/timeframe_selector.dart';
import 'package:nokken/src/features/mood_tracker/models/mood_entry.dart';
import 'package:nokken/src/features/mood_tracker/providers/mood_state.dart';

class MonthlyTrendsCard extends ConsumerWidget {
  final String timeframe;

  const MonthlyTrendsCard({
    super.key,
    required this.timeframe,
  });

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // Get mood entries from the provider
    final moodEntries = ref.watch(moodEntriesProvider);
    final filteredEntries = TimeframeSelector.filterByTimeframe(
      items: moodEntries,
      timeframe: timeframe,
      getDate: (entry) => entry.date,
    );

    // Check if we have enough data
    final hasEnoughData = filteredEntries.length >= 30;

    return Card(
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
      elevation: 2,
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // Header
            Row(
              children: [
                Container(
                  padding: const EdgeInsets.all(8),
                  decoration: BoxDecoration(
                    color: Colors.blue.withAlpha(30),
                    shape: BoxShape.circle,
                  ),
                  child: const Icon(
                    Icons.trending_up,
                    color: Colors.blue,
                    size: 24,
                  ),
                ),
                const SizedBox(width: 12),
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        'Monthly Trends',
                        style: AppTextStyles.titleMedium,
                      ),
                      Text(
                        'Mood averages over months',
                        style: AppTextStyles.bodySmall.copyWith(
                          color: AppColors.onSurfaceVariant,
                        ),
                      ),
                    ],
                  ),
                ),
              ],
            ),
            const SizedBox(height: 16),

            // Content
            if (hasEnoughData) ...[
              SizedBox(
                height: 200,
                child: _buildMonthlyAverageChart(filteredEntries),
              ),
            ] else ...[
              // Empty state
              Text(
                'Not enough data to analyze monthly trends. Continue tracking your mood for at least a month to see monthly averages.',
                style: AppTextStyles.bodyMedium,
              ),
            ],
          ],
        ),
      ),
    );
  }

  Widget _buildMonthlyAverageChart(List<MoodEntry> entries) {
    try {
      // Get the date range for the past 12 months
      final now = DateTime.now();
      final twelveMonthsAgo = DateTime(now.year - 1, now.month, now.day);

      // Group entries by month
      final Map<String, List<double>> moodByMonth = {};

      // Initialize past 12 months
      for (int i = 0; i < 12; i++) {
        final month = DateTime(now.year, now.month - i, 1);
        final monthKey =
            '${month.year}-${month.month.toString().padLeft(2, '0')}';
        moodByMonth[monthKey] = [];
      }

      // Process each entry
      for (final entry in entries) {
        // Skip entries older than 12 months
        if (entry.date.isBefore(twelveMonthsAgo)) {
          continue;
        }

        final monthKey =
            '${entry.date.year}-${entry.date.month.toString().padLeft(2, '0')}';
        // Convert mood to a 0-4 scale (4 = Great, 0 = Bad)
        final moodValue = 4 - entry.mood.index.toDouble();

        if (moodByMonth.containsKey(monthKey)) {
          moodByMonth[monthKey]!.add(moodValue);
        } else {
          moodByMonth[monthKey] = [moodValue];
        }
      }

      // Calculate monthly averages
      final List<Map<String, dynamic>> monthlyData = [];

      // Sort months chronologically (oldest first)
      final sortedMonths = moodByMonth.keys.toList()..sort();

      for (final monthKey in sortedMonths) {
        final monthMoods = moodByMonth[monthKey] ?? [];
        if (monthMoods.isNotEmpty) {
          final avgMood =
              monthMoods.reduce((a, b) => a + b) / monthMoods.length;

          // Extract year and month from key
          final parts = monthKey.split('-');
          final year = int.parse(parts[0]);
          final month = int.parse(parts[1]);

          // Get month name
          final monthName = DateFormat('MMM').format(DateTime(year, month));

          monthlyData.add({
            'month': monthName,
            'year': year,
            'averageMood': avgMood,
            'count': monthMoods.length,
          });
        }
      }

      // Check if we have any data to show
      if (monthlyData.isEmpty) {
        return Center(
          child: Text(
            'No monthly data available',
            style: AppTextStyles.bodyMedium,
          ),
        );
      }

      // Only keep the most recent 6 months with data
      final recentMonths =
          monthlyData.reversed.take(6).toList().reversed.toList();

      return LineChart(
        LineChartData(
          gridData: FlGridData(
            show: true,
            drawVerticalLine: true,
            horizontalInterval: 1,
            verticalInterval: 1,
            getDrawingHorizontalLine: (value) {
              return FlLine(
                color: AppColors.onSurfaceVariant.withAlpha(40),
                strokeWidth: 1,
              );
            },
            getDrawingVerticalLine: (value) {
              return FlLine(
                color: AppColors.onSurfaceVariant.withAlpha(40),
                strokeWidth: 1,
              );
            },
          ),
          titlesData: FlTitlesData(
            show: true,
            rightTitles: AxisTitles(
              sideTitles: SideTitles(showTitles: false),
            ),
            topTitles: AxisTitles(
              sideTitles: SideTitles(showTitles: false),
            ),
            bottomTitles: AxisTitles(
              sideTitles: SideTitles(
                showTitles: true,
                getTitlesWidget: (value, meta) {
                  if (value >= 0 && value < recentMonths.length) {
                    return Padding(
                      padding: const EdgeInsets.only(top: 8.0),
                      child: Text(
                        recentMonths[value.toInt()]['month'] ?? '',
                        style: AppTextStyles.bodySmall,
                      ),
                    );
                  }
                  return const SizedBox();
                },
                reservedSize: 30,
              ),
            ),
            leftTitles: AxisTitles(
              sideTitles: SideTitles(
                showTitles: true,
                interval: 1,
                getTitlesWidget: (value, meta) {
                  if (value >= 0 && value <= 4 && value % 1 == 0) {
                    String moodLabel;
                    switch (value.toInt()) {
                      case 0:
                        moodLabel = 'Bad';
                        break;
                      case 1:
                        moodLabel = 'Meh';
                        break;
                      case 2:
                        moodLabel = 'OK';
                        break;
                      case 3:
                        moodLabel = 'Good';
                        break;
                      case 4:
                        moodLabel = 'Great';
                        break;
                      default:
                        moodLabel = '';
                    }

                    return Padding(
                      padding: const EdgeInsets.only(right: 8.0),
                      child: Text(
                        moodLabel,
                        style: AppTextStyles.bodySmall,
                      ),
                    );
                  }
                  return const SizedBox();
                },
                reservedSize: 50,
              ),
            ),
          ),
          borderData: FlBorderData(
            show: true,
            border: Border.all(color: AppColors.onSurfaceVariant.withAlpha(40)),
          ),
          minX: 0,
          maxX: recentMonths.length - 1,
          minY: 0,
          maxY: 4,
          lineBarsData: [
            LineChartBarData(
              spots: recentMonths.asMap().entries.map((entry) {
                // Handle potential missing averageMood values safely
                final averageMood =
                    entry.value['averageMood'] as double? ?? 2.0;
                return FlSpot(
                  entry.key.toDouble(),
                  averageMood.clamp(0.0, 4.0), // Ensure value is in range
                );
              }).toList(),
              isCurved: true,
              gradient: const LinearGradient(
                colors: [Colors.blue, Colors.purple],
              ),
              barWidth: 3,
              isStrokeCapRound: true,
              dotData: FlDotData(
                show: true,
                getDotPainter: (spot, percent, barData, index) {
                  return FlDotCirclePainter(
                    radius: 5,
                    color: _getMoodColor(spot.y),
                    strokeWidth: 2,
                    strokeColor: Colors.white,
                  );
                },
              ),
              belowBarData: BarAreaData(
                show: true,
                gradient: LinearGradient(
                  colors: [
                    Colors.blue.withAlpha(60),
                    Colors.purple.withAlpha(20),
                  ],
                ),
              ),
            ),
          ],
          lineTouchData: LineTouchData(
            touchTooltipData: LineTouchTooltipData(
              tooltipBgColor: Colors.blueGrey.withAlpha(180),
              getTooltipItems: (List<LineBarSpot> touchedSpots) {
                return touchedSpots.map((spot) {
                  final index = spot.x.toInt();
                  if (index < 0 || index >= recentMonths.length) {
                    return LineTooltipItem(
                      'Invalid data point',
                      const TextStyle(color: AppTheme.white),
                    );
                  }

                  final month = recentMonths[index]['month'] ?? 'Unknown';
                  final year =
                      recentMonths[index]['year']?.toString() ?? 'Unknown';
                  final avgMood = spot.y.toStringAsFixed(1);
                  final count = recentMonths[index]['count']?.toString() ?? '0';

                  return LineTooltipItem(
                    '$month $year\nAvg: $avgMood (from $count entries)',
                    const TextStyle(
                      color: AppTheme.white,
                      fontWeight: FontWeight.bold,
                    ),
                  );
                }).toList();
              },
            ),
          ),
        ),
      );
    } catch (e) {
      return Center(
        child: Text(
          'Error creating chart: $e',
          style: AppTextStyles.bodyMedium,
        ),
      );
    }
  }

  Color _getMoodColor(double moodValue) {
    // Round to nearest integer
    final moodIndex = moodValue.round();

    switch (moodIndex) {
      case 0:
        return Colors.red.shade300; // Bad
      case 1:
        return Colors.orange.shade300; // Meh
      case 2:
        return Colors.yellow.shade300; // Okay
      case 3:
        return Colors.lime.shade300; // Good
      case 4:
        return Colors.green.shade300; // Great
      default:
        return Colors.blue.shade300; // Fallback
    }
  }
}
