// SPDX-FileCopyrightText: © 2025 Nøkken.io // 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 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 _createSampleMedications() { final now = DateTime.now(); final allDays = Set.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 _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}'); } }