// SPDX-FileCopyrightText: © 2025 Nøkken.io <nokken.io@proton.me>
// SPDX-License-Identifier: AGPL-3.0
//
//  medication_taken_provider.dart
//  Provider to manage taken medications with database persistence
//
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/scheduler/services/medication_schedule_service.dart';
import 'package:nokken/src/core/services/database/database_service.dart';

/// Notifier for tracking which medications have been taken
class MedicationTakenNotifier extends StateNotifier<Set<String>> {
  final DatabaseService _databaseService;

  MedicationTakenNotifier({required DatabaseService databaseService})
      : _databaseService = databaseService,
        super({});

  /// Load taken medications for a specific date
  Future<void> loadTakenMedicationsForDate(DateTime date) async {
    try {
      final takenMeds = await _databaseService.getTakenMedicationsForDate(date);
      state = takenMeds;
    } catch (e) {
      // Handle error - perhaps log it, but continue with empty set
      state = {};
    }
  }

  /// Set a medication as taken or not taken
  ///
  /// @param dose The medication dose being taken or untaken
  /// @param taken Whether the medication is being marked as taken (true) or untaken (false)
  /// @param customKey An optional custom key to use for the database.
  ///        Used for handling multiple doses of the same medication at the same time slot
  Future<void> setMedicationTaken(MedicationDose dose, bool taken,
      {String? customKey}) async {
    // Use the provided custom key or generate a standard one
    final key = customKey ?? dose.toKey();

    try {
      // Update database using the dose details but saving with the custom key if provided
      await _databaseService.setMedicationTakenWithCustomKey(
          dose.medicationId, dose.date, dose.timeSlot, taken, customKey);

      // Update state
      if (taken) {
        state = {...state, key};
      } else {
        state = {...state}..remove(key);
      }
    } catch (e) {
      // If database update fails, don't update state
      // Could add error handling here
    }
  }

  /// Clear expired data (optional maintenance function)
  Future<void> clearOldData(int olderThanDays) async {
    final cutoffDate = DateTime.now().subtract(Duration(days: olderThanDays));
    try {
      await _databaseService.deleteTakenMedicationsOlderThan(cutoffDate);
      // No need to update state since we don't track old data in memory
    } catch (e) {
      // Handle error
    }
  }
}

//----------------------------------------------------------------------------
// PROVIDER DEFINITIONS
//----------------------------------------------------------------------------

/// Provider for tracking which medications have been taken
final medicationTakenProvider =
    StateNotifierProvider<MedicationTakenNotifier, Set<String>>((ref) {
  final databaseService = ref.watch(databaseServiceProvider);
  return MedicationTakenNotifier(databaseService: databaseService);
});

/// Provider to get medications scheduled for a specific date
final medicationsForDateProvider =
    Provider.family<List<Medication>, DateTime>((ref, date) {
  final allMedications = ref.watch(medicationsProvider);
  return MedicationScheduleService.getMedicationsForDate(allMedications, date);
});

/// Provider to get medication doses scheduled for a specific date
final dosesForDateProvider =
    Provider.family<List<MedicationDose>, DateTime>((ref, date) {
  final medications = ref.watch(medicationsForDateProvider(date));
  return MedicationScheduleService.getDosesForDate(medications, date);
});

/// Provider to check if a specific medication dose is taken
final isDoseTakenProvider = Provider.family<bool, MedicationDose>((ref, dose) {
  final takenMedications = ref.watch(medicationTakenProvider);
  return takenMedications.contains(dose.toKey());
});

/// Provider that groups medications by time slot for a specific date
final medicationsByTimeSlotProvider =
    Provider.family<Map<String, List<Medication>>, DateTime>((ref, date) {
  final medications = ref.watch(medicationsForDateProvider(date));
  return MedicationScheduleService.groupMedicationsByTimeSlot(medications);
});
