// SPDX-FileCopyrightText: © 2025 Nøkken.io <nokken.io@proton.me>
// SPDX-License-Identifier: AGPL-3.0
//
//  year_screen.dart
//  Yearly view of all 365 days
//
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:nokken/src/core/constants/date_constants.dart';
import 'package:nokken/src/core/ui/widgets/shared_widgets.dart';
import 'package:nokken/src/core/utils/get_icons_colors.dart';
import 'package:nokken/src/core/utils/date_time_formatter.dart';
import 'package:nokken/src/features/medication_tracker/providers/medication_state.dart';
import 'package:nokken/src/features/mood_tracker/models/mood_entry.dart';
import 'package:nokken/src/features/mood_tracker/providers/mood_state.dart';
import 'package:nokken/src/features/mood_tracker/utils/mood_utils.dart';
import 'package:nokken/src/core/ui/theme/app_icons.dart';
import 'package:nokken/src/core/ui/theme/app_theme.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/features/medication_tracker/models/medication.dart';
import 'package:nokken/src/features/scheduler/services/medication_schedule_service.dart';
import 'package:nokken/src/features/bloodwork_tracker/models/bloodwork.dart';
import 'package:nokken/src/features/bloodwork_tracker/providers/bloodwork_state.dart';
import 'package:nokken/src/features/scheduler/screens/calendar_screen.dart';

//==============================================================================
// MAIN YEAR SCREEN
//==============================================================================

/// Year screen that displays a 12-month overview calendar
///
/// Shows all days of the year with visual indicators for medications,
/// appointments, and mood entries. Allows the user to select any day
/// to return to the monthly calendar view.
class YearScreen extends ConsumerStatefulWidget {
  /// The initially selected date when opening the screen
  final DateTime initialDate;

  const YearScreen({
    super.key,
    required this.initialDate,
  });

  @override
  ConsumerState<YearScreen> createState() => _YearScreenState();
}

class _YearScreenState extends ConsumerState<YearScreen> {
  late int _selectedYear;
  late Map<DateTime, MoodRating> _moodEntryDates;
  late Set<DateTime> _injectionDueDates;
  late Set<DateTime> _patchDueDates;
  late Set<DateTime> _oralMedicationDates;
  late Set<DateTime> _topicalMedicationDates;
  late Set<DateTime> _bloodworkDates;

  //----------------------------------------------------------------------------
  // LIFECYCLE METHODS
  //----------------------------------------------------------------------------

  @override
  void initState() {
    super.initState();
    _selectedYear = widget.initialDate.year;
    _updateMoodEntryDates();
    _updateMedicalDates();
  }

  //----------------------------------------------------------------------------
  // DATA LOADING & PROCESSING METHODS
  //----------------------------------------------------------------------------

  /// Updates the map of dates that have mood entries
  ///
  /// Loads all mood entries from the provider and creates a map
  /// with normalized dates as keys and mood ratings as values.
  void _updateMoodEntryDates() {
    final moodEntries = ref.read(moodEntriesProvider);
    _moodEntryDates = {};

    // Populate map with normalized dates and their mood ratings
    for (final entry in moodEntries) {
      final normalizedDate = DateTime(
        entry.date.year,
        entry.date.month,
        entry.date.day,
      );
      _moodEntryDates[normalizedDate] = entry.mood;
    }
  }

  /// Updates all medical-related dates
  ///
  /// Loads and calculates dates for all types of medications and appointments
  void _updateMedicalDates() {
    // Get medications
    final medications = ref.read(medicationsProvider);

    // Update injection dates
    _injectionDueDates =
        MedicationScheduleService.calculateInjectionDueDates(medications);

    // Update patch, oral, and topical dates
    _patchDueDates =
        _calculateMedicationDueDates(medications, MedicationType.patch);
    _oralMedicationDates =
        _calculateMedicationDueDates(medications, MedicationType.oral);
    _topicalMedicationDates =
        _calculateMedicationDueDates(medications, MedicationType.topical);

    // Update bloodwork dates
    _bloodworkDates = ref.read(bloodworkDatesProvider);
  }

  Set<DateTime> _calculateMedicationDueDates(
      List<Medication> medications, MedicationType medicationType) {
    Set<DateTime> dueDates = {};

    // Filter for medications of the specified type
    final filteredMedications = medications
        .where((med) => med.medicationType == medicationType)
        .toList();

    if (filteredMedications.isEmpty) {
      return dueDates; // No medications of this type found
    }

    // Get dates for current year
    final startDate = DateTime(_selectedYear, 1, 1);
    final endDate = DateTime(_selectedYear, 12, 31);

    // Use DateTimeFormatter for date iteration
    for (final date in DateTimeFormatter.dateRange(startDate, endDate)) {
      for (final medication in filteredMedications) {
        // Check if this medication is scheduled for this date
        final medsForDay =
            MedicationScheduleService.getMedicationsForDate([medication], date);
        if (medsForDay.isNotEmpty) {
          dueDates.add(date); // Already normalized by dateRange
          break; // Only add each date once
        }
      }
    }

    return dueDates;
  }

  //----------------------------------------------------------------------------
  // DATE CHECKING METHODS
  //----------------------------------------------------------------------------

  /// Gets the mood rating for a specific date if it exists
  MoodRating? _getMoodForDate(DateTime date) {
    // Normalize date for comparison
    final normalizedDate = DateTime(date.year, date.month, date.day);

    // Check if this date has a mood entry
    for (final entry in _moodEntryDates.entries) {
      if (DateTime(
        entry.key.year,
        entry.key.month,
        entry.key.day,
      ).isAtSameMomentAs(normalizedDate)) {
        return entry.value;
      }
    }
    return null;
  }

  /// Checks if a date has an injection due
  bool _hasInjectionDue(DateTime date) {
    // Compare just the date part, not time
    final normalizedDate = DateTime(date.year, date.month, date.day);
    return _injectionDueDates.any((injectionDate) {
      final normalizedInjectionDate = DateTime(
        injectionDate.year,
        injectionDate.month,
        injectionDate.day,
      );
      return normalizedInjectionDate.isAtSameMomentAs(normalizedDate);
    });
  }

  /// Checks if a date has a patch due
  bool _hasPatchDue(DateTime date) {
    final normalizedDate = DateTime(date.year, date.month, date.day);
    return _patchDueDates.any((patchDate) {
      final normalizedPatchDate = DateTime(
        patchDate.year,
        patchDate.month,
        patchDate.day,
      );
      return normalizedPatchDate.isAtSameMomentAs(normalizedDate);
    });
  }

  /// Checks if a date has oral medication due
  bool _hasOralMedicationDue(DateTime date) {
    final normalizedDate = DateTime(date.year, date.month, date.day);
    return _oralMedicationDates.any((oralDate) {
      final normalizedOralDate = DateTime(
        oralDate.year,
        oralDate.month,
        oralDate.day,
      );
      return normalizedOralDate.isAtSameMomentAs(normalizedDate);
    });
  }

  /// Checks if a date has topical medication due
  bool _hasTopicalMedicationDue(DateTime date) {
    final normalizedDate = DateTime(date.year, date.month, date.day);
    return _topicalMedicationDates.any((topicalDate) {
      final normalizedTopicalDate = DateTime(
        topicalDate.year,
        topicalDate.month,
        topicalDate.day,
      );
      return normalizedTopicalDate.isAtSameMomentAs(normalizedDate);
    });
  }

  /// Checks if a date has bloodwork tests
  bool _hasBloodworkOnDate(DateTime date) {
    // Compare just the date part, not time
    final normalizedDate = DateTime(date.year, date.month, date.day);
    return _bloodworkDates.any((labDate) {
      final normalizedLabDate = DateTime(
        labDate.year,
        labDate.month,
        labDate.day,
      );
      return normalizedLabDate.isAtSameMomentAs(normalizedDate);
    });
  }

  /// Gets the appointment type(a.k.a what color to display)
  /// for a given date
  /// order of priority:
  /// surgery > appointment > bloodwork
  AppointmentType? _getAppointmentTypeForDate(DateTime date) {
    // Normalize date for comparison
    final normalizedDate = DateTime(date.year, date.month, date.day);

    // Get bloodwork records for this date
    final bloodworkRecords = ref.read(bloodworkRecordsProvider).where((record) {
      final recordDate =
          DateTime(record.date.year, record.date.month, record.date.day);
      return recordDate.isAtSameMomentAs(normalizedDate);
    }).toList();

    // Prioritize by appointment type
    if (bloodworkRecords.isNotEmpty) {
      if (bloodworkRecords
          .any((r) => r.appointmentType == AppointmentType.surgery)) {
        return AppointmentType.surgery;
      } else if (bloodworkRecords
          .any((r) => r.appointmentType == AppointmentType.appointment)) {
        return AppointmentType.appointment;
      } else {
        return AppointmentType.bloodwork;
      }
    }
    return null;
  }

  //----------------------------------------------------------------------------
  // UI BUILDING METHODS
  //----------------------------------------------------------------------------

  @override
  Widget build(BuildContext context) {
    // Update data when the UI is rebuilt
    _updateMoodEntryDates();
    _updateMedicalDates();

    return Scaffold(
      appBar: AppBar(
        title: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            IconButton(
              icon: Icon(AppIcons.getIcon('chevron_left')),
              onPressed: () {
                setState(() {
                  _selectedYear--;
                });
              },
            ),
            Text('$_selectedYear', style: AppTextStyles.titleLarge),
            IconButton(
              icon: Icon(AppIcons.getIcon('chevron_right')),
              onPressed: () {
                setState(() {
                  _selectedYear++;
                });
              },
            ),
          ],
        ),
        centerTitle: true,
      ),
      body: SingleChildScrollView(
        child: Column(
          children: [
            // Add view mode tabs
            _buildViewModeTabs(),

            // Year calendar
            Padding(
              padding: const EdgeInsets.all(16.0),
              child: Row(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: List.generate(12, (index) {
                  final month = index + 1;
                  return Expanded(
                      child: _buildMonthColumn(month, _selectedYear));
                }),
              ),
            ),
          ],
        ),
      ),
    );
  }

  /// Builds tabs for switching between medical and mood views
  Widget _buildViewModeTabs() {
    final viewMode = ref.watch(calendarViewModeProvider);

    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
      child: Row(
        children: [
          Expanded(
            child: _buildViewModeTab(
              context,
              icon: Icons.medication,
              label: 'Medical',
              isSelected: viewMode == CalendarViewMode.medical,
              onTap: () {
                ref.read(calendarViewModeProvider.notifier).state =
                    CalendarViewMode.medical;
              },
            ),
          ),
          SharedWidgets.horizontalSpace(8),
          Expanded(
            child: _buildViewModeTab(
              context,
              icon: Icons.mood,
              label: 'Mood',
              isSelected: viewMode == CalendarViewMode.mood,
              onTap: () {
                ref.read(calendarViewModeProvider.notifier).state =
                    CalendarViewMode.mood;
              },
            ),
          ),
        ],
      ),
    );
  }

  /// Builds a single view mode tab with appropriate styling
  Widget _buildViewModeTab(
    BuildContext context, {
    required IconData icon,
    required String label,
    required bool isSelected,
    required VoidCallback onTap,
  }) {
    return Material(
      color: isSelected ? AppColors.primary : AppColors.surfaceContainer,
      borderRadius: BorderRadius.circular(8),
      child: InkWell(
        onTap: onTap,
        borderRadius: BorderRadius.circular(8),
        child: Padding(
          padding: const EdgeInsets.symmetric(vertical: 12),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Icon(
                icon,
                color: isSelected ? AppColors.onPrimary : AppColors.onSurface,
                size: 20,
              ),
              SharedWidgets.horizontalSpace(8),
              Text(
                label,
                style: TextStyle(
                  color: isSelected ? AppColors.onPrimary : AppColors.onSurface,
                  fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  /// Builds a column for a specific month showing all days
  Widget _buildMonthColumn(int month, int year) {
    final daysInMonth = DateTime(year, month + 1, 0).day;
    final monthName = DateConstants.months[month - 1];

    return Container(
      margin: const EdgeInsets.symmetric(horizontal: 4),
      child: Column(
        children: [
          // Month header
          Container(
            padding: const EdgeInsets.symmetric(vertical: 8),
            decoration: BoxDecoration(
              color: AppColors.primary,
              borderRadius: BorderRadius.circular(8),
            ),
            alignment: Alignment.center,
            child: Text(
              monthName,
              style: AppTextStyles.titleSmall.copyWith(
                color: AppColors.onPrimary,
                fontWeight: FontWeight.bold,
                fontSize: 9,
              ),
            ),
          ),
          SharedWidgets.verticalSpace(8),

          // Days of the month
          ...List.generate(daysInMonth, (dayIndex) {
            final day = dayIndex + 1;
            final date = DateTime(year, month, day);
            return _buildDayCircle(date);
          }),
        ],
      ),
    );
  }

  /// Builds a circle for a specific day with coloring based on view mode
  ///
  /// Colors the day based on:
  /// - Medical view: surgery > appointment > bloodwork > injection > patch > oral > topical
  /// - Mood view: based on the recorded mood value
  Widget _buildDayCircle(DateTime date) {
    final viewMode = ref.watch(calendarViewModeProvider);
    final isToday = DateTime.now().year == date.year &&
        DateTime.now().month == date.month &&
        DateTime.now().day == date.day;

    // Calculate color for the day
    Color circleColor = Colors.transparent;
    Color textColor = AppColors.onSurface;

    if (viewMode == CalendarViewMode.mood) {
      // Mood mode coloring
      final moodRating = _getMoodForDate(date);

      if (moodRating != null) {
        // If there's a mood entry, use its color
        circleColor = MoodUtils.getMoodColor(moodRating);
        textColor = AppTheme.white;
      }
    } else {
      // Medical mode coloring - follow priority order (injections > patches > oral > topical)
      final hasBloodwork = _hasBloodworkOnDate(date);
      final hasInjection = _hasInjectionDue(date);
      final hasPatch = _hasPatchDue(date);
      final hasOral = _hasOralMedicationDue(date);
      final hasTopical = _hasTopicalMedicationDue(date);

      if (hasBloodwork) {
        final appointmentType = _getAppointmentTypeForDate(date);
        if (appointmentType != null) {
          circleColor = GetIconsColors.getAppointmentColor(appointmentType);
          textColor = AppTheme.white;
        }
      } else if (hasInjection) {
        circleColor = AppColors.injection;
        textColor = AppTheme.white;
      } else if (hasPatch) {
        circleColor = AppColors.patch;
        textColor = AppTheme.white;
      } else if (hasOral) {
        circleColor = AppColors.oralMedication.withAlpha(140);
        textColor = AppTheme.white;
      } else if (hasTopical) {
        circleColor = AppColors.topical.withAlpha(140);
        textColor = AppTheme.white;
      }
    }

    // Create border for today's date
    final border =
        isToday ? Border.all(color: AppColors.primary, width: 2) : null;

    return GestureDetector(
      onTap: () {
        // Navigate back to the calendar screen with this date selected
        Navigator.pop(context, date);
      },
      child: Container(
        height: 28,
        margin: const EdgeInsets.symmetric(vertical: 2),
        decoration: BoxDecoration(
          shape: BoxShape.circle,
          color: circleColor,
          border: border,
        ),
        alignment: Alignment.center,
        child: Text(
          '${date.day}',
          style: TextStyle(
            fontSize: 12,
            color: textColor,
            fontWeight: isToday || circleColor != Colors.transparent
                ? FontWeight.bold
                : FontWeight.normal,
          ),
        ),
      ),
    );
  }
}
