// SPDX-FileCopyrightText: © 2025 Nøkken.io <nokken.io@proton.me>
// SPDX-License-Identifier: AGPL-3.0
//
//  daily_tracker_screen.dart
//  Screen for tracking daily medications and appointments- with mood logging
//
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:nokken/src/features/medication_tracker/models/medication.dart';
import 'package:nokken/src/features/medication_tracker/models/medication_dose.dart';
import 'package:nokken/src/features/medication_tracker/providers/medication_state.dart';
import 'package:nokken/src/features/medication_tracker/providers/medication_taken_provider.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/mood_tracker/models/mood_entry.dart';
import 'package:nokken/src/features/mood_tracker/providers/mood_state.dart';
import 'package:nokken/src/features/mood_tracker/screens/mood_tracker_screen.dart';
import 'package:nokken/src/features/mood_tracker/widgets/mood_quick_selector.dart';
import 'package:nokken/src/core/services/navigation/navigation_service.dart';
import 'package:nokken/src/core/ui/widgets/shared_widgets.dart';
import 'package:nokken/src/core/ui/theme/app_theme.dart';
import 'package:nokken/src/core/ui/theme/app_icons.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/utils/date_time_formatter.dart';
import 'package:nokken/src/core/utils/get_labels.dart';
import 'package:nokken/src/core/utils/get_icons_colors.dart';
import 'package:nokken/src/core/utils/list_extensions.dart';
import 'package:nokken/src/core/ui/widgets/dialog_service.dart';
import 'package:nokken/src/features/scheduler/services/as_needed_medication_dialog.dart';
import 'package:nokken/src/features/medication_tracker/providers/as_needed_medication_provider.dart';

//==============================================================================
// PROVIDERS
//==============================================================================

/// Provider to track the currently selected date
final selectedDateProvider = StateProvider<DateTime>((ref) => DateTime.now());

/// Provider to track slide direction for day-change animation
final slideDirectionProvider = StateProvider<bool>((ref) => true);

/// Provider for bloodwork records on selected date
final bloodworkForSelectedDateProvider =
    Provider.family<List<Bloodwork>, DateTime>((ref, date) {
  final bloodworkRecords = ref.watch(bloodworkRecordsProvider);
  return bloodworkRecords.where((record) {
    final recordDate =
        DateTime(record.date.year, record.date.month, record.date.day);
    final selectedDate = DateTime(date.year, date.month, date.day);
    return recordDate.isAtSameMomentAs(selectedDate);
  }).toList();
});

/// Provider to get unique medication doses with index
final uniqueMedicationDosesProvider =
    Provider.family<List<(MedicationDose, int, Medication)>, DateTime>(
        (ref, date) {
  final medications = ref.watch(medicationsForDateProvider(date));
  final result = <(MedicationDose, int, Medication)>[];

  for (final med in medications) {
    final Map<String, List<DateTime>> timeSlots = {};

    for (final time in med.timeOfDay) {
      final timeSlot =
          DateTimeFormatter.formatTimeToAMPM(TimeOfDay.fromDateTime(time));

      if (!timeSlots.containsKey(timeSlot)) {
        timeSlots[timeSlot] = [];
      }

      timeSlots[timeSlot]!.add(time);
    }

    for (final entry in timeSlots.entries) {
      final timeSlot = entry.key;
      final times = entry.value;

      for (int i = 0; i < times.length; i++) {
        final dose = MedicationDose(
          medicationId: med.id,
          date: date,
          timeSlot: timeSlot,
        );

        result.add((dose, i, med));
      }
    }
  }

  // Sort by time slot
  result.sort((a, b) {
    final timeA = DateTimeFormatter.parseTimeString(a.$1.timeSlot);
    final timeB = DateTimeFormatter.parseTimeString(b.$1.timeSlot);
    return (timeA.hour * 60 + timeA.minute) - (timeB.hour * 60 + timeB.minute);
  });

  return result;
});

/// Provider to check if a specific medication dose with index is taken
final isUniqueDoseTakenProvider =
    Provider.family<bool, (MedicationDose, int)>((ref, params) {
  final takenMedications = ref.watch(medicationTakenProvider);
  final dose = params.$1;
  final index = params.$2;

  final key =
      '${dose.medicationId}-${dose.date.toIso8601String()}-${dose.timeSlot}-$index';

  if (takenMedications.contains(key)) {
    return true;
  }

  return false;
});

/// Provider to check if there's an existing mood entry for the selected date
final moodEntryExistsProvider = Provider.family<bool, DateTime>((ref, date) {
  final normalizedDate = DateTime(date.year, date.month, date.day);
  final entries = ref.watch(moodEntriesProvider);

  return entries.any((entry) =>
      DateTime(entry.date.year, entry.date.month, entry.date.day)
          .isAtSameMomentAs(normalizedDate));
});

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

/// Daily tracker screen for medication and appointment management
///
/// Shows all scheduled items for a single day including medications,
/// appointments, and mood entries. Allows users to mark medications as taken
/// and navigate to detailed screens for each item.
class DailyTrackerScreen extends ConsumerStatefulWidget {
  const DailyTrackerScreen({super.key});

  @override
  _DailyTrackerScreenState createState() => _DailyTrackerScreenState();
}

class _DailyTrackerScreenState extends ConsumerState<DailyTrackerScreen> {
  //----------------------------------------------------------------------------
  // LIFECYCLE METHODS
  //----------------------------------------------------------------------------

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _loadTakenMedicationsForCurrentDate();
  }

  //----------------------------------------------------------------------------
  // DATA LOADING METHODS
  //----------------------------------------------------------------------------

  /// Loads which medications have been taken for the current date
  void _loadTakenMedicationsForCurrentDate() {
    final selectedDate = ref.read(selectedDateProvider);
    final normalizedDate =
        DateTime(selectedDate.year, selectedDate.month, selectedDate.day);
    ref
        .read(medicationTakenProvider.notifier)
        .loadTakenMedicationsForDate(normalizedDate);
  }

  //----------------------------------------------------------------------------
  // NAVIGATION METHODS
  //----------------------------------------------------------------------------

  /// Changes the date by the specified number of days (-1, 1)
  void _changeDate(WidgetRef ref, int days) {
    ref.read(slideDirectionProvider.notifier).state = days > 0;
    ref.read(selectedDateProvider.notifier).update(
          (state) => state.add(Duration(days: days)),
        );
  }

  /// Shows the dialog to select and take an as-needed medication
  void _showAsNeededMedicationDialog() {
    showDialog(
      context: context,
      builder: (context) => AsNeededMedicationDialog(
        onTakeMedication: (medication, time) {
          _recordAsNeededMedication(medication, time);
        },
      ),
    );
  }

  /// Records that an as-needed medication was taken

  Future<void> _recordAsNeededMedication(
      Medication medication, DateTime time) async {
    final timeOfDay = TimeOfDay.fromDateTime(time);
    final timeSlot = DateTimeFormatter.formatTimeToAMPM(timeOfDay);

    // Important: Use the SAME date format that you're using in the selectedDateProvider
    final selectedDate = ref.read(selectedDateProvider);

    print("DEBUG: Recording as-needed medication: ${medication.name}");
    print("DEBUG: Selected date: $selectedDate");
    print("DEBUG: Time: $time, TimeSlot: $timeSlot");

    final dose = MedicationDose(
      medicationId: medication.id,
      date: selectedDate, // Make sure we use the selectedDate
      timeSlot: timeSlot,
    );

    // Generate a unique key that includes a timestamp to ensure uniqueness
    final uniqueTimestamp = DateTime.now().millisecondsSinceEpoch.toString();
    final customKey =
        '${dose.medicationId}-${dose.date.toIso8601String()}-$timeSlot-$uniqueTimestamp';

    print("DEBUG: Generated key: $customKey");

    // Mark the medication as taken
    await ref.read(medicationTakenProvider.notifier).setMedicationTaken(
          dose,
          true,
          customKey: customKey,
        );

    // Update medication quantity if tracking is enabled
    if (medication.currentQuantity > 0) {
      ref
          .read(medicationStateProvider.notifier)
          .updateMedicationQuantity(medication, true);
    }

    // Force refresh the as-needed doses provider
    ref.invalidate(asNeededDosesForDateProvider(selectedDate));

    print("DEBUG: Provider invalidated for date: $selectedDate");

    // Show confirmation
    if (mounted) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('${medication.name} recorded as taken'),
          backgroundColor: AppColors.tertiary,
          duration: const Duration(seconds: 2),
        ),
      );
    }

    // Reload the taken medications to refresh the UI
    _loadTakenMedicationsForCurrentDate();
  }

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

  @override
  Widget build(BuildContext context) {
    final selectedDate = ref.watch(selectedDateProvider);
    final bloodworkRecords =
        ref.watch(bloodworkForSelectedDateProvider(selectedDate));

    ref.listen(selectedDateProvider, (previous, next) {
      if (previous != next) {
        final normalizedDate = DateTime(next.year, next.month, next.day);
        ref
            .read(medicationTakenProvider.notifier)
            .loadTakenMedicationsForDate(normalizedDate);
      }
    });

    final uniqueDoses = ref.watch(uniqueMedicationDosesProvider(selectedDate));
    final Map<String, List<(MedicationDose, int, Medication)>> groupedDoses =
        {};

    for (final doseWithIndex in uniqueDoses) {
      final timeSlot = doseWithIndex.$1.timeSlot;
      if (!groupedDoses.containsKey(timeSlot)) {
        groupedDoses[timeSlot] = [];
      }
      groupedDoses[timeSlot]!.add(doseWithIndex);
    }

    final sortedTimeSlots = groupedDoses.keys.toList()
      ..sort((a, b) => DateTimeFormatter.compareTimeSlots(a, b));

    final List<MedicationTimeGroup> medicationTimeGroups = [];

    for (final timeSlot in sortedTimeSlots) {
      final dosesForTimeSlot = groupedDoses[timeSlot]!;
      final medications = dosesForTimeSlot.map((e) => e.$3).toList();
      medicationTimeGroups.add(MedicationTimeGroup(
        timeSlot: timeSlot,
        medications: medications,
        doseIndexes: dosesForTimeSlot.map((e) => (e.$1, e.$2)).toList(),
      ));
    }

    final bool hasScheduledItems =
        medicationTimeGroups.isNotEmpty || bloodworkRecords.isNotEmpty;

    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          onPressed: () => NavigationService.goToCalendar(context).then((_) {
            _loadTakenMedicationsForCurrentDate();
          }),
          icon: Icon(AppIcons.getIcon('calendar')),
        ),
        title: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            IconButton(
              icon: Icon(AppIcons.getIcon('chevron_left')),
              onPressed: () => _changeDate(ref, -1),
            ),
            Flexible(
              child: Text(
                DateTimeFormatter.formatDateMMMDDYYYY(selectedDate),
                style: Theme.of(context).textTheme.titleMedium,
                textAlign: TextAlign.center,
                overflow: TextOverflow.ellipsis,
              ),
            ),
            IconButton(
              icon: Icon(AppIcons.getIcon('chevron_right')),
              onPressed: () => _changeDate(ref, 1),
            ),
          ],
        ),
        actions: [
          PopupMenuButton<String>(
            icon: Icon(AppIcons.getIcon('add')),
            tooltip: 'Add options',
            onSelected: (String value) {
              if (value == 'as-needed') {
                _showAsNeededMedicationDialog();
              } else if (value == 'medication') {
                NavigationService.goToMedicationAddEdit(context);
              } else if (value == 'appointment') {
                NavigationService.goToBloodworkAddEdit(context);
              }
            },
            itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
              const PopupMenuItem<String>(
                value: 'as-needed',
                child: Text('Add take-as-needed'),
              ),
              const PopupMenuItem<String>(
                value: 'medication',
                child: Text('Add medication'),
              ),
              const PopupMenuItem<String>(
                value: 'appointment',
                child: Text('Add appointment'),
              ),
            ],
          ),
        ],
      ),
      body: Column(
        children: [
          Expanded(
            child: AnimatedSwitcher(
              duration: const Duration(milliseconds: 200),
              transitionBuilder: (Widget child, Animation<double> animation) {
                bool isForward = ref.watch(slideDirectionProvider);
                if (child.key == ValueKey<DateTime>(selectedDate)) {
                  // Entering widget
                  return SlideTransition(
                    position: Tween<Offset>(
                      begin: Offset(isForward ? 1.0 : -1.0, 0.0),
                      end: Offset.zero,
                    ).animate(animation),
                    child: child,
                  );
                } else {
                  // Exiting widget
                  return SlideTransition(
                    position: Tween<Offset>(
                      begin: Offset(isForward ? -1.0 : 1.0, 0.0),
                      end: Offset.zero,
                    ).animate(animation),
                    child: child,
                  );
                }
              },
              child: _DailyScheduleList(
                key: ValueKey<DateTime>(selectedDate),
                medicationTimeGroups: medicationTimeGroups,
                bloodworkRecords: bloodworkRecords,
                selectedDate: selectedDate,
                hasScheduledItems: hasScheduledItems,
              ),
            ),
          ),
        ],
      ),
    );
  }
}

//==============================================================================
// SUPPORTING WIDGETS
//==============================================================================

/// Daily schedule list showing mood, medications, and appointments
class _DailyScheduleList extends ConsumerWidget {
  const _DailyScheduleList({
    super.key,
    required this.medicationTimeGroups,
    required this.bloodworkRecords,
    required this.selectedDate,
    required this.hasScheduledItems,
  });

  final List<MedicationTimeGroup> medicationTimeGroups;
  final List<Bloodwork> bloodworkRecords;
  final DateTime selectedDate;
  final bool hasScheduledItems;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // Check if there's a mood entry for this day
    final moodEntries = ref.watch(moodEntriesProvider);

    // Use firstWhereOrNull extension to safely find the entry
    final moodEntry = moodEntries.firstWhereOrNull((entry) => DateTime(
            entry.date.year, entry.date.month, entry.date.day)
        .isAtSameMomentAs(
            DateTime(selectedDate.year, selectedDate.month, selectedDate.day)));

    // Check for scheduled content
    final bool hasMedContent =
        medicationTimeGroups.isNotEmpty || bloodworkRecords.isNotEmpty;

    // Combine medications and appointments into a chronologically sorted list
    final sortedItems = _getSortedScheduleItems();

    // Use the proper provider for as-needed medications
    final asNeededDoses = ref.watch(asNeededDosesForDateProvider(selectedDate));
    print(
        "DEBUG: In _DailyScheduleList.build: Found ${asNeededDoses.length} as-needed doses");

    // Convert from provider's AsNeededDose to local _AsNeededDose
    final List<_AsNeededDose> localAsNeededDoses = asNeededDoses.map((dose) {
      print(
          "DEBUG: Converting dose: ${dose.medication.name}, timeSlot: ${dose.timeSlot}, key: ${dose.key}");
      return _AsNeededDose(
        medication: dose.medication,
        timeSlot: dose.timeSlot,
        key: dose.key,
      );
    }).toList();

    print(
        "DEBUG: After conversion, have ${localAsNeededDoses.length} local doses");

    if (localAsNeededDoses.isNotEmpty) {
      print(
          "DEBUG: Will render ${localAsNeededDoses.length} as-needed doses in UI");
      // Check the first one to make sure it's valid
      print(
          "DEBUG: First dose: ${localAsNeededDoses.first.medication.name}, timeSlot: ${localAsNeededDoses.first.timeSlot}");
    }

    // Show the sorted schedule with mood tracker at the top
    return ListView(
      padding: AppTheme.standardCardPadding,
      children: [
        MoodQuickSelector(
          selectedDate: selectedDate,
          existingEntry: moodEntry,
          onNavigateToMoodTracker: (MoodEntry? preSelectedEntry) {
            _navigateToMoodTracker(context, ref, preSelectedEntry);
          },
        ),

        // Divider after mood section
        const Divider(height: 32),

        // Conditional message for no content
        if (!hasMedContent && localAsNeededDoses.isEmpty)
          Text(
            'Nothing scheduled for this day',
            textAlign: TextAlign.center,
            style: Theme.of(context).textTheme.bodyLarge,
          ),

        // Only spread sorted items if they exist
        if (hasMedContent)
          ...sortedItems.map((item) {
            if (item is _AppointmentItem) {
              return _buildAppointmentSection(item.bloodwork);
            } else if (item is _MedicationGroupItem) {
              return _TimeGroupItem(
                timeGroup: item.timeGroup,
                selectedDate: selectedDate,
              );
            }
            return const SizedBox.shrink();
          }),

        // If there are as-needed medications taken, show them in a separate section
        if (localAsNeededDoses.isNotEmpty) ...[
          // Add a divider if there was scheduled content
          if (hasMedContent) const Divider(height: 32),

          // As-needed medications section
          Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Padding(
                padding: const EdgeInsets.symmetric(
                  vertical: AppTheme.spacing,
                  horizontal: AppTheme.spacing,
                ),
                child: Row(
                  children: [
                    Icon(
                      AppIcons.getIcon('medication'),
                      color: AppColors.tertiary,
                    ),
                    SharedWidgets.horizontalSpace(),
                    Text(
                      'As-Needed Medications',
                      style: AppTextStyles.titleMedium.copyWith(
                        color: AppColors.tertiary,
                      ),
                    ),
                  ],
                ),
              ),

              // List of as-needed doses
              ...localAsNeededDoses.map((dose) => _AsNeededDoseItem(
                    dose: dose,
                    onDelete: () => _deleteAsNeededDose(context, ref, dose),
                  )),
            ],
          ),
        ],
      ],
    );
  }

  /// Navigate to the mood tracker screen with optional pre-selected mood
  void _navigateToMoodTracker(
      BuildContext context, WidgetRef ref, MoodEntry? preSelectedEntry) async {
    // Check if we have an existing entry that should override the pre-selection
    final existingEntry = preSelectedEntry?.id != null
        ? preSelectedEntry
        : ref.read(moodEntriesProvider).firstWhereOrNull((entry) =>
            DateTime(entry.date.year, entry.date.month, entry.date.day)
                .isAtSameMomentAs(DateTime(
                    selectedDate.year, selectedDate.month, selectedDate.day)));

    // Navigate to mood tracker screen with either the existing entry or the pre-selected mood
    await Navigator.of(context).push(
      MaterialPageRoute(
        builder: (context) => MoodTrackerScreen(
          selectedDate: selectedDate,
          existingEntry: existingEntry ?? preSelectedEntry,
        ),
      ),
    );

    // Reload mood entries when returning
    if (ref.exists(moodStateProvider)) {
      ref.read(moodStateProvider.notifier).loadMoodEntries();
    }
  }

  /// Builds the appointment section UI
  Widget _buildAppointmentSection(Bloodwork bloodwork) {
    // Format the appointment time
    final timeOfDay = TimeOfDay.fromDateTime(bloodwork.date);
    final timeStr = DateTimeFormatter.formatTimeToAMPM(timeOfDay);

    // Get the appointment color
    final appointmentColor =
        GetIconsColors.getAppointmentColor(bloodwork.appointmentType);

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        // Appointment time header
        Padding(
          padding: const EdgeInsets.symmetric(vertical: AppTheme.spacing),
          child: Row(
            children: [
              Icon(DateTimeFormatter.getTimeIcon(timeStr),
                  size: 20, color: appointmentColor),
              SharedWidgets.horizontalSpace(),
              Text(timeStr,
                  style: AppTextStyles.titleMedium
                      .copyWith(color: appointmentColor)),
            ],
          ),
        ),
        // Appointment card
        _AppointmentCard(bloodwork: bloodwork),
      ],
    );
  }

  /// Sorts schedule items chronologically
  ///
  /// Returns a combined list of medication groups and appointments
  /// ordered by their time of day
  List<_ScheduleItem> _getSortedScheduleItems() {
    final List<_ScheduleItem> items = [];

    // Add medication groups
    for (final group in medicationTimeGroups) {
      items.add(_MedicationGroupItem(timeGroup: group));
    }

    // Add bloodwork appointments
    for (final bloodwork in bloodworkRecords) {
      items.add(_AppointmentItem(bloodwork: bloodwork));
    }

    // Sort by time
    items.sort((a, b) {
      final timeA = a is _MedicationGroupItem
          ? DateTimeFormatter.parseTimeString(a.timeGroup.timeSlot)
          : TimeOfDay.fromDateTime((a as _AppointmentItem).bloodwork.date);

      final timeB = b is _MedicationGroupItem
          ? DateTimeFormatter.parseTimeString(b.timeGroup.timeSlot)
          : TimeOfDay.fromDateTime((b as _AppointmentItem).bloodwork.date);

      return (timeA.hour * 60 + timeA.minute) -
          (timeB.hour * 60 + timeB.minute);
    });

    return items;
  }

  /// Handle deletion of an as-needed medication entry
  void _deleteAsNeededDose(
      BuildContext context, WidgetRef ref, _AsNeededDose dose) {
    DialogService.showDeleteDialog(
      context: context,
      ref: ref,
      itemName: "${dose.medication.name} entry",
      onDelete: () async {
        try {
          // Get parsed dose from provider helper
          final doseToDelete = parseDoseFromKey(dose.key);

          if (doseToDelete != null) {
            // Remove the dose from the database
            ref.read(medicationTakenProvider.notifier).setMedicationTaken(
                  doseToDelete,
                  false,
                  customKey: dose.key,
                );

            // Add back to the medication quantity
            final medication = dose.medication;
            if (medication.currentQuantity >= 0) {
              ref
                  .read(medicationStateProvider.notifier)
                  .updateMedicationQuantity(medication, false);
            }

            // Show confirmation
            if (context.mounted) {
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(
                  content: Text('Removed ${medication.name} entry'),
                  duration: const Duration(seconds: 2),
                ),
              );
            }
          }
        } catch (e) {
          // Show error
          if (context.mounted) {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                content: Text('Failed to remove entry: $e'),
                backgroundColor: AppColors.error,
              ),
            );
          }
        }
      },
    );
  }
}

/// Card displaying a medical appointment
class _AppointmentCard extends StatelessWidget {
  final Bloodwork bloodwork;

  const _AppointmentCard({required this.bloodwork});

  @override
  Widget build(BuildContext context) {
    final isDateInFuture = DateTime(
      bloodwork.date.year,
      bloodwork.date.month,
      bloodwork.date.day,
    ).isAfter(DateTime(
      DateTime.now().year,
      DateTime.now().month,
      DateTime.now().day,
    ));

    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // Appointment type icon
            GetIconsColors.getAppointmentIconWithColor(
                bloodwork.appointmentType),

            SharedWidgets.verticalSpace(AppTheme.doubleSpacing),

            // Appointment details
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  InkWell(
                    onTap: () => NavigationService.goToBloodworkAddEdit(
                      context,
                      bloodwork: bloodwork,
                    ),
                    child: Row(
                      children: [
                        Text(
                          GetLabels.getAppointmentTypeText(
                              bloodwork.appointmentType),
                          style: AppTextStyles.titleLarge,
                        ),
                        if (isDateInFuture) ...[
                          SharedWidgets.horizontalSpace(),
                          Container(
                            padding: const EdgeInsets.symmetric(
                                horizontal: 8, vertical: 2),
                            decoration: BoxDecoration(
                              color: AppColors.info.withAlpha(20),
                              borderRadius: BorderRadius.circular(12),
                              border: Border.all(
                                  color: AppColors.info.withAlpha(50)),
                            ),
                            child: Text(
                              'Scheduled',
                              style: TextStyle(
                                fontSize: 12,
                                color: AppColors.info,
                                fontWeight: FontWeight.w500,
                              ),
                            ),
                          ),
                        ],
                      ],
                    ),
                  ),

                  // Display location if available
                  if (bloodwork.location?.isNotEmpty == true) ...[
                    SharedWidgets.verticalSpace(),
                    Row(
                      children: [
                        Icon(
                          AppIcons.getOutlined('location'),
                          size: 16,
                          color: AppTheme.grey,
                        ),
                        SharedWidgets.verticalSpace(6),
                        Text(
                          bloodwork.location!,
                          style: AppTextStyles.bodyMedium,
                        ),
                      ],
                    ),
                  ],

                  // Display doctor if available
                  if (bloodwork.doctor?.isNotEmpty == true) ...[
                    SharedWidgets.verticalSpace(4),
                    Row(
                      children: [
                        Icon(
                          AppIcons.getIcon('profile'),
                          size: 16,
                          color: AppTheme.grey,
                        ),
                        SharedWidgets.verticalSpace(6),
                        Text(
                          bloodwork.doctor!,
                          style: AppTextStyles.bodyMedium,
                        ),
                      ],
                    ),
                  ],

                  // Display notes if any
                  if (bloodwork.notes?.isNotEmpty == true) ...[
                    SharedWidgets.verticalSpace(),
                    Text(
                      'Notes: ${bloodwork.notes}',
                      style: AppTextStyles.bodySmall,
                      maxLines: 2,
                      overflow: TextOverflow.ellipsis,
                    ),
                  ],
                ],
              ),
            )
          ],
        ),
      ),
    );
  }
}

/// Group of medications scheduled for the same time
class _TimeGroupItem extends StatelessWidget {
  const _TimeGroupItem({
    required this.timeGroup,
    required this.selectedDate,
  });

  final MedicationTimeGroup timeGroup;
  final DateTime selectedDate;

  @override
  Widget build(BuildContext context) {
    // Determine the group color based on medication types
    Color timeGroupColor = _getTimeGroupColor();

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        // Time slot header
        Padding(
          padding: const EdgeInsets.symmetric(vertical: AppTheme.spacing),
          child: Row(
            children: [
              Icon(DateTimeFormatter.getTimeIcon(timeGroup.timeSlot),
                  size: 20, color: timeGroupColor),
              SharedWidgets.horizontalSpace(),
              Text(
                timeGroup.timeSlot,
                style:
                    AppTextStyles.titleMedium.copyWith(color: timeGroupColor),
              ),
            ],
          ),
        ),
        // List of medications for this time slot (each med is its own card)
        Column(
          children: List.generate(timeGroup.doseIndexes.length, (i) {
            final doseWithIndex = timeGroup.doseIndexes[i];
            final medication = timeGroup.medications[i];
            return _MedicationListTile(
              medication: medication,
              dose: doseWithIndex.$1,
              doseIndex: doseWithIndex.$2,
              selectedDate: selectedDate,
            );
          }),
        ),
      ],
    );
  }

  /// Determine color based on the types of medications in this group
  Color _getTimeGroupColor() {
    // Use a set to track unique medication types
    final Set<MedicationType> medicationTypes =
        timeGroup.medications.map((med) => med.medicationType).toSet();

    // If there's only one type, return its specific color
    if (medicationTypes.length == 1) {
      return GetIconsColors.getMedicationColor(medicationTypes.first);
    }

    // If there are multiple types, return primary
    return AppColors.primary;
  }
}

/// Individual medication item with take/untake functionality
class _MedicationListTile extends ConsumerWidget {
  const _MedicationListTile({
    required this.medication,
    required this.dose,
    required this.doseIndex,
    required this.selectedDate,
  });

  final Medication medication;
  final MedicationDose dose;
  final int doseIndex;
  final DateTime selectedDate;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // Check if this specific instance is taken
    final isTaken = ref.watch(isUniqueDoseTakenProvider((dose, doseIndex)));

    // Add dose index indicator if this is not the first dose at this time
    final String doseIndicator =
        doseIndex > 0 ? ' (Dose ${doseIndex + 1})' : '';

    return Padding(
      padding: const EdgeInsets.only(bottom: 4.0),
      child: Card(
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: IntrinsicHeight(
            // Ensures all columns have the same height
            child: Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                // Medication type icon
                GetIconsColors.getMedicationIconWithColor(
                    medication.medicationType),

                SharedWidgets.horizontalSpace(AppTheme.doubleSpacing),

                // Medication details
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      // Medication name with link
                      InkWell(
                        onTap: () => NavigationService.goToMedicationDetails(
                          context,
                          medication: medication,
                        ),
                        child: Row(
                          children: [
                            Flexible(
                              child: Text(
                                medication.name + doseIndicator,
                                style: AppTextStyles.titleLarge,
                                overflow: TextOverflow.ellipsis,
                              ),
                            ),

                            // Show refill indicator if needed
                            if (medication.needsRefill()) ...[
                              SharedWidgets.horizontalSpace(),
                              Container(
                                padding: const EdgeInsets.symmetric(
                                    horizontal: 8, vertical: 2),
                                decoration: BoxDecoration(
                                  color: AppColors.error.withAlpha(20),
                                  borderRadius: BorderRadius.circular(12),
                                  border: Border.all(
                                      color: AppColors.error.withAlpha(50)),
                                ),
                                child: Text(
                                  'Refill Needed',
                                  style: TextStyle(
                                    fontSize: 12,
                                    color: AppColors.error,
                                    fontWeight: FontWeight.w500,
                                  ),
                                ),
                              ),
                            ],
                          ],
                        ),
                      ),

                      SharedWidgets.verticalSpace(),

                      // Site viewer
                      if (medication.medicationType ==
                              MedicationType.injection &&
                          medication.injectionDetails?.siteRotation != null &&
                          medication.injectionDetails!.siteRotation!.sites
                              .isNotEmpty) ...[
                        SharedWidgets.horizontalSpace(),
                        InkWell(
                          onTap: () {
                            _showInjectionSiteDialog(context, medication);
                          },
                          child: Row(
                            children: [
                              SharedWidgets.horizontalSpace(6),
                              Text(
                                'Next Site: ${GetLabels.getBodyAreaText(medication.injectionDetails!.siteRotation!.nextSite.bodyArea)} ${medication.injectionDetails!.siteRotation!.nextSite.siteNumber}',
                                style: AppTextStyles.bodyMedium.copyWith(
                                  color: GetIconsColors.getMedicationColor(
                                      medication.medicationType),
                                  decoration: TextDecoration.underline,
                                ),
                              ),
                              SharedWidgets.horizontalSpace(6),
                              Icon(
                                AppIcons.getIcon('arrow_circle_right'),
                                size: 16,
                                color: GetIconsColors.getMedicationColor(
                                    medication.medicationType),
                              ),
                            ],
                          ),
                        ),
                      ],

                      // Medication dosage with type specific language
                      SharedWidgets.verticalSpace(),
                      Text(
                        GetLabels.formatDosageText(medication),
                        style: AppTextStyles.bodyMedium,
                      ),

                      // Show quantity with warning color if refill needed
                      if (medication.currentQuantity > 0) ...[
                        SharedWidgets.verticalSpace(4),
                        Row(
                          children: [
                            Icon(
                              Icons.inventory_2_outlined,
                              size: 16,
                              color: medication.needsRefill()
                                  ? AppColors.error
                                  : AppTheme.grey,
                            ),
                            SharedWidgets.verticalSpace(6),
                            Text(
                              'Remaining: ${medication.currentQuantity}',
                              style: AppTextStyles.bodyMedium.copyWith(
                                color: medication.needsRefill()
                                    ? AppColors.error
                                    : null,
                              ),
                            ),
                          ],
                        ),
                      ],

                      // Show taken status
                      SharedWidgets.verticalSpace(),
                      Text(
                        isTaken
                            ? GetLabels.getCompletedText(
                                medication.medicationType)
                            : GetLabels.getPendingText(
                                medication.medicationType),
                        style: AppTextStyles.bodyMedium.copyWith(
                          fontWeight: FontWeight.w500,
                          color: isTaken ? AppColors.tertiary : AppTheme.grey,
                        ),
                      ),
                    ],
                  ),
                ),

                // Spacing between main content and checkbox column
                SharedWidgets.horizontalSpace(16),

                // Right column for the checkbox - centered vertically with main content
                Container(
                  margin: const EdgeInsets.all(16),
                  child: Center(
                    // Ensures vertical centering
                    child: SizedBox(
                      width: 36,
                      height: 36,
                      child: Transform.scale(
                        scale:
                            1.7, // Scale up the checkbox for better visibility
                        child: Checkbox(
                          value: isTaken,
                          onChanged: (bool? value) =>
                              _handleTakenChange(value, ref),
                          fillColor: WidgetStateProperty.resolveWith((states) {
                            if (states.contains(WidgetState.selected)) {
                              return AppColors.tertiary;
                            }
                            return AppTheme.white.withAlpha(100);
                          }),
                          checkColor: AppColors.onTertiary,
                          materialTapTargetSize: MaterialTapTargetSize
                              .padded, // Increases tap target
                        ),
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  /// Shows the injection site viewer dialog for injection medications
  void _showInjectionSiteDialog(BuildContext context, Medication medication) {
    if (medication.injectionDetails?.siteRotation == null ||
        medication.injectionDetails!.siteRotation!.sites.isEmpty) {
      return;
    }

    NavigationService.goToInjectionSiteViewer(
      context,
      medication: medication,
    );
  }

  /// Handles toggling a medication's taken status
  ///
  /// Updates the database and state providers, handles quantity tracking,
  /// and manages injection site rotation when applicable
  void _handleTakenChange(bool? value, WidgetRef ref) {
    if (value == null) return;

    // Show warning message if not enough medication, but still allow marking as taken
    if (value &&
        medication.currentQuantity <= 0 &&
        medication.refillThreshold > 0) {
      ScaffoldMessenger.of(ref.context).showSnackBar(
        SnackBar(
          content: const Text('Not enough medication remaining'),
          backgroundColor: AppColors.error,
          action: SnackBarAction(
            label: 'Refill',
            textColor: AppTheme.white,
            onPressed: () {
              // Navigate to medication edit screen
              NavigationService.goToMedicationAddEdit(
                ref.context,
                medication: medication,
              );
            },
          ),
          duration: const Duration(seconds: 4),
        ),
      );
    }

    // Create a key that includes the dose index
    final key =
        '${dose.medicationId}-${dose.date.toIso8601String()}-${dose.timeSlot}-$doseIndex';

    // Update taken medications in database and state
    ref.read(medicationTakenProvider.notifier).setMedicationTaken(
          dose,
          value,
          customKey: key,
        );

    // Update medication quantity if quantity > 0
    if (medication.currentQuantity > 0) {
      ref
          .read(medicationStateProvider.notifier)
          .updateMedicationQuantity(medication, value);
    }

    // Handle injection site rotation
    _handleInjectionSiteRotation(value, ref);
  }

  /// Handles advancing or reversing injection site rotation
  ///
  /// Called when marking an injection as taken or untaken
  void _handleInjectionSiteRotation(bool value, WidgetRef ref) {
    // Only process for injections with site rotation configured
    if (medication.medicationType == MedicationType.injection &&
        medication.injectionDetails?.siteRotation != null &&
        medication.injectionDetails!.siteRotation!.sites.isNotEmpty) {
      if (value) {
        // Being marked as taken - advance to next site
        final updatedRotation =
            medication.injectionDetails!.siteRotation!.advance();
        final updatedDetails = medication.injectionDetails!.copyWith(
          siteRotation: updatedRotation,
        );
        final updatedMedication = medication.copyWith(
          injectionDetails: updatedDetails,
        );
        ref
            .read(medicationStateProvider.notifier)
            .updateMedication(updatedMedication);
      } else {
        // Being unmarked as taken - go back to previous site
        final currentRotation = medication.injectionDetails!.siteRotation!;
        final sites = currentRotation.sites;
        final currentIndex = currentRotation.currentSiteIndex;
        final previousIndex = (currentIndex - 1 + sites.length) % sites.length;

        final updatedRotation = InjectionSiteRotation(
          sites: sites,
          currentSiteIndex: previousIndex,
        );
        final updatedDetails = medication.injectionDetails!.copyWith(
          siteRotation: updatedRotation,
        );
        final updatedMedication = medication.copyWith(
          injectionDetails: updatedDetails,
        );
        ref
            .read(medicationStateProvider.notifier)
            .updateMedication(updatedMedication);
      }
    }
  }
}

class _AsNeededDoseItem extends StatelessWidget {
  final _AsNeededDose dose;
  final VoidCallback onDelete;

  const _AsNeededDoseItem({
    required this.dose,
    required this.onDelete,
  });

  @override
  Widget build(BuildContext context) {
    print("DEBUG: Building _AsNeededDoseItem for ${dose.medication.name}");

    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // Time indicator column
            Column(
              children: [
                Icon(
                  DateTimeFormatter.getTimeIcon(dose.timeSlot),
                  color: AppColors.tertiary,
                ),
                SharedWidgets.verticalSpace(4),
                Text(
                  dose.timeSlot,
                  style: TextStyle(
                    fontWeight: FontWeight.bold,
                    fontSize: 12,
                  ),
                ),
              ],
            ),

            SharedWidgets.horizontalSpace(16),

            // Medication information
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Expanded(
                        child: Text(
                          dose.medication.name,
                          style: AppTextStyles.titleMedium,
                          overflow: TextOverflow.ellipsis,
                        ),
                      ),
                      IconButton(
                        icon: Icon(
                          AppIcons.getIcon('delete'),
                          color: AppColors.error,
                          size: 20,
                        ),
                        onPressed: onDelete,
                        tooltip: 'Remove Entry',
                        padding: EdgeInsets.zero,
                        constraints: BoxConstraints(),
                      ),
                    ],
                  ),
                  SharedWidgets.verticalSpace(4),
                  Text(
                    dose.medication.dosage,
                    style: AppTextStyles.bodyMedium,
                  ),
                  SharedWidgets.verticalSpace(4),
                  Text(
                    'Taken',
                    style: AppTextStyles.bodyMedium.copyWith(
                      fontWeight: FontWeight.w500,
                      color: AppColors.tertiary,
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

//==============================================================================
// DATA MODELS & HELPER CLASSES
//==============================================================================

/// Model for as-needed doses taken on a specific day
class _AsNeededDose {
  final Medication medication;
  final String timeSlot;
  final String key; // Original key from database for deletion

  _AsNeededDose({
    required this.medication,
    required this.timeSlot,
    required this.key,
  });
}

/// Base class for schedule items
abstract class _ScheduleItem {}

/// A medication group item
class _MedicationGroupItem extends _ScheduleItem {
  final MedicationTimeGroup timeGroup;

  _MedicationGroupItem({required this.timeGroup});
}

/// An appointment item
class _AppointmentItem extends _ScheduleItem {
  final Bloodwork bloodwork;

  _AppointmentItem({required this.bloodwork});
}

/// Data model for grouping medications by time slot
class MedicationTimeGroup {
  /// The formatted time slot (e.g., "9:00 AM")
  final String timeSlot;

  /// List of medications scheduled for this time slot
  final List<Medication> medications;

  /// List of medication doses with their indexes
  final List<(MedicationDose, int)> doseIndexes;

  const MedicationTimeGroup({
    required this.timeSlot,
    List<Medication>? medications,
    List<(MedicationDose, int)>? doseIndexes,
  })  : medications = medications ?? const [],
        doseIndexes = doseIndexes ?? const [];
}
