package no.naiv.meddetsamme.alarm import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import java.time.LocalDate import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import no.naiv.meddetsamme.data.MedDatabase import no.naiv.meddetsamme.domain.ScheduleEngine import no.naiv.meddetsamme.notify.Notifications /** * Daily derived-state check: low stock (inventory ÷ scheduled rate) and * prescription renewal (rx expiry, independent of stock — decision #9). * One digest notification, not one per med. */ class SupplyCheckReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val pending = goAsync() CoroutineScope(Dispatchers.IO).launch { try { check(context) } finally { AlarmScheduler(context).armSupplyCheck() // chain the next daily check pending.finish() } } } private suspend fun check(context: Context) { val db = MedDatabase.get(context) val today = LocalDate.now() val lines = mutableListOf() // Per inventory item: consumption is the SUM across all active regimens // drawing from it — one shared box drains faster than either alone. val byItem = db.medicationDao().getActive().groupBy { it.item.id } for ((_, meds) in byItem) { val item = meds.first().item var rate = 0.0 for (med in meds) rate += ScheduleEngine.dailyConsumption(db.doseTimeDao().getForMed(med.med.id)) if (ScheduleEngine.needsRefill(item.stockUnits, rate, item.lowStockLeadDays)) { val days = ScheduleEngine.daysOfSupply(item.stockUnits, rate) lines += "${item.name}: lager for ${days?.toInt() ?: 0} dager" } if (ScheduleEngine.needsRenewal(item.rxExpiryEpochDay, today)) { val expired = item.rxExpiryEpochDay!! < today.toEpochDay() lines += if (expired) "${item.name}: resept utløpt" else "${item.name}: resept må fornyes" } } if (lines.isNotEmpty()) { Notifications.post( context, Notifications.SUPPLY_NOTIFICATION_ID, Notifications.buildSupplyNotification(context, lines), ) } } }