package de.ladkau.deckinadash.notify

import android.content.Context
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import de.ladkau.deckinadash.data.DeckConfig
import java.util.Calendar
import java.util.concurrent.TimeUnit

/**
 * WorkManager analog of watch/src/c/notify.c's notify_reschedule(): (re)schedules
 * a one-shot wakeup for the next occurrence of `config.notifyHour:notifyMinute`
 * in the device's local time (today if not yet passed, tomorrow otherwise),
 * or only cancels if notifications are disabled. See ReadingNotificationWorker
 * for the self-rescheduling chain this kicks off.
 *
 * Call once per app launch (DeckInADashApplication.onCreate()) and on every
 * config save (ConfigViewModel.save()) - same two call sites notify_reschedule()
 * itself requires, for the same reason (settings may have changed).
 */
object NotificationScheduler {
    private const val WORK_NAME = "daily_reading_notification"

    fun reschedule(context: Context, config: DeckConfig) {
        val workManager = WorkManager.getInstance(context)
        if (!config.notifyEnabled) {
            workManager.cancelUniqueWork(WORK_NAME)
            return
        }
        val delayMillis = millisUntilNext(config.notifyHour, config.notifyMinute)
        val request = OneTimeWorkRequestBuilder<ReadingNotificationWorker>()
            .setInitialDelay(delayMillis, TimeUnit.MILLISECONDS)
            .build()
        // REPLACE is the WorkManager analog of notify_reschedule()'s own
        // cancel-then-reschedule - guarantees no duplicate chains.
        workManager.enqueueUniqueWork(WORK_NAME, ExistingWorkPolicy.REPLACE, request)
    }

    private fun millisUntilNext(hour: Int, minute: Int): Long {
        val now = Calendar.getInstance()
        val target = (now.clone() as Calendar).apply {
            set(Calendar.HOUR_OF_DAY, hour)
            set(Calendar.MINUTE, minute)
            set(Calendar.SECOND, 0)
            set(Calendar.MILLISECOND, 0)
        }
        if (!target.after(now)) {
            target.add(Calendar.DAY_OF_YEAR, 1)
        }
        return target.timeInMillis - now.timeInMillis
    }
}
