// SPDX-FileCopyrightText: © 2025 Nøkken.io <nokken.io@proton.me>
// SPDX-License-Identifier: AGPL-3.0
//
// medication_data_generator.dart
//
import 'dart:math' show Random;
import 'package:flutter/material.dart';
import 'package:nokken/src/core/constants/date_constants.dart';
import 'package:nokken/src/core/services/database/database_service.dart';
import 'package:nokken/src/features/medication_tracker/models/medication.dart';
import 'package:nokken/src/features/medication_tracker/models/medication_dose.dart';

/// A tool class to generate historical medication data
class MedicationDataGenerator {
  final DatabaseService databaseService;

  MedicationDataGenerator(this.databaseService);

  /// Generate sample medications and adherence data for 365 days
  Future<void> generateMedicationData() async {
    final random = Random();

    // Start date: 364 days ago from today
    final endDate = DateTime.now();
    final startDate = endDate.subtract(const Duration(days: 364));

    debugPrint(
        'Generating medication data from ${startDate.toIso8601String()} to ${endDate.toIso8601String()}');

    // Check existing medications and add more if needed
    final existingMeds = await databaseService.getAllMedications();
    debugPrint('Found ${existingMeds.length} existing medications');

    // We want to have at least 5 medications
    if (existingMeds.length < 5) {
      debugPrint('Creating additional sample medications...');
      final targetCount = 5 - existingMeds.length;

      // Get sample medications and only use as many as needed
      final allSampleMeds = _createSampleMedications();
      final medsToAdd = allSampleMeds.take(targetCount).toList();

      for (final med in medsToAdd) {
        await databaseService.insertMedication(med);
      }
      debugPrint('Created ${medsToAdd.length} additional medications.');
    }

    // Get all medications
    final allMeds = await databaseService.getAllMedications();

    // Generate taking records for each medication
    for (final med in allMeds) {
      debugPrint('Generating adherence data for ${med.name}...');

      // Set adherence rate based on medication type
      double adherenceRate;
      if (med.medicationType == MedicationType.injection ||
          med.medicationType == MedicationType.patch) {
        // Higher adherence for injections and patches (96-98%)
        adherenceRate = 0.96 + (random.nextDouble() * 0.02);
      } else {
        // Lower adherence for pills and topical (95-97%)
        adherenceRate = 0.95 + (random.nextDouble() * 0.02);
      }

      debugPrint(
          'Using adherence rate of ${(adherenceRate * 100).toStringAsFixed(1)}% for ${med.name}');

      // Generate records for each day
      await _generateMedicationRecords(
          med, startDate, endDate, adherenceRate, random);
    }

    debugPrint('Successfully generated medication adherence data.');
  }

  /// Create 5 sample medications of different types
  List<Medication> _createSampleMedications() {
    final now = DateTime.now();
    final allDays = Set<String>.from(DateConstants.dayMap.values);

    // Common morning and evening times
    final morning = DateTime(now.year, now.month, now.day, 8, 0);
    final evening = DateTime(now.year, now.month, now.day, 20, 0);
    final noon = DateTime(now.year, now.month, now.day, 12, 0);

    return [
      // Pill 1: Daily antidepressant in the morning
      Medication(
        name: 'Sertraline',
        dosage: '50mg',
        startDate: DateTime.now().subtract(const Duration(days: 400)),
        frequency: 1,
        timeOfDay: [morning],
        daysOfWeek: allDays,
        currentQuantity: 28,
        refillThreshold: 7,
        medicationType: MedicationType.oral,
        oralSubtype: OralSubtype.tablets,
        notes: 'SSRI antidepressant',
        doctor: 'Dr. Smith',
        pharmacy: 'Local Pharmacy',
      ),

      // Pill 2: Multivitamin taken once daily
      Medication(
        name: 'Multivitamin',
        dosage: '1 tablet',
        startDate: DateTime.now().subtract(const Duration(days: 380)),
        frequency: 1,
        timeOfDay: [noon],
        daysOfWeek: allDays,
        currentQuantity: 60,
        refillThreshold: 10,
        medicationType: MedicationType.oral,
        oralSubtype: OralSubtype.tablets,
      ),

      // Topical: Gel applied twice daily
      Medication(
        name: 'Topical Treatment',
        dosage: 'Thin layer',
        startDate: DateTime.now().subtract(const Duration(days: 390)),
        frequency: 2,
        timeOfDay: [morning, evening],
        daysOfWeek: allDays,
        currentQuantity: 1,
        refillThreshold: 1,
        medicationType: MedicationType.topical,
        topicalSubtype: TopicalSubtype.gel,
      ),

      // Patch: Applied weekly
      Medication(
        name: 'Hormone Patch',
        dosage: '1 patch',
        startDate: DateTime.now().subtract(const Duration(days: 395)),
        frequency: 1,
        timeOfDay: [morning],
        daysOfWeek: {'Su'}, // Applied on Sundays
        currentQuantity: 4,
        refillThreshold: 2,
        medicationType: MedicationType.patch,
      ),

      // Injection: Intramuscular, biweekly
      Medication(
        name: 'Hormone Injection',
        dosage: '0.5ml',
        startDate: DateTime.now().subtract(const Duration(days: 392)),
        frequency: 1,
        timeOfDay: [evening],
        daysOfWeek: {'F'}, // Injected on Fridays
        currentQuantity: 2,
        refillThreshold: 1,
        medicationType: MedicationType.injection,
        injectionDetails: InjectionDetails(
          drawingNeedleType: '18G 1.5"',
          drawingNeedleCount: 8,
          drawingNeedleRefills: 2,
          injectingNeedleType: '23G 1"',
          injectingNeedleCount: 8,
          injectingNeedleRefills: 2,
          syringeType: '3ml Luer Lock',
          syringeCount: 8,
          syringeRefills: 2,
          injectionSiteNotes: 'Rotate between thighs and glutes',
          frequency: InjectionFrequency.biweekly,
          subtype: InjectionSubtype.intramuscular,
          siteRotation: InjectionSiteRotation(
            sites: [
              InjectionSite(siteNumber: 1, bodyArea: InjectionBodyArea.thigh),
              InjectionSite(siteNumber: 2, bodyArea: InjectionBodyArea.thigh),
            ],
            currentSiteIndex: 0,
          ),
        ),
        doctor: 'Dr. Johnson',
        pharmacy: 'Specialty Pharmacy',
      ),
    ];
  }

  /// Generate medication taking records based on specified adherence patterns
  Future<void> _generateMedicationRecords(
      Medication medication,
      DateTime startDate,
      DateTime endDate,
      double adherenceRate,
      Random random) async {
    int recordCount = 0;

    // For each day in the range
    for (int i = 0; i <= 364; i++) {
      final date = startDate.add(Duration(days: i));

      // Check if this medication is scheduled for this day
      if (medication.isDueOnDate(date)) {
        // For each time slot
        for (int timeIndex = 0; timeIndex < medication.frequency; timeIndex++) {
          final timeSlot = timeIndex < medication.timeOfDay.length
              ? medication.timeOfDay[timeIndex].hour.toString()
              : '$timeIndex';

          // Create a proper MedicationDose object
          final dose = MedicationDose(
            medicationId: medication.id,
            date: date,
            timeSlot: timeSlot,
          );

          // Generate a custom key from the dose plus a unique identifier
          final customKey = '${dose.toKey()}-historical-$i';

          // Determine if the dose was taken based on adherence rate
          final wasTaken = random.nextDouble() <= adherenceRate;

          // Save the taking record
          await databaseService.setMedicationTakenWithCustomKey(
              medication.id, date, timeSlot, wasTaken, customKey);

          if (wasTaken) {
            recordCount++;
          }
        }
      }
    }

    debugPrint('Generated $recordCount taking records for ${medication.name}');
  }
}
