package es.freetimelab.pluriwave

import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.core.app.NotificationManagerCompat

class AlarmScheduler(private val context: Context) {
    private val alarmManager =
        context.getSystemService(Context.ALARM_SERVICE) as AlarmManager

    fun scheduleAlarm(id: String, title: String, triggerAtMillis: Long, preNoticeAtMillis: Long) {
        val alarmIntent = PendingIntent.getBroadcast(
            context,
            requestCode(id, 1),
            Intent(context, PluriWaveAlarmReceiver::class.java).apply {
                action = PluriWaveAlarmReceiver.ACTION_FIRE
                putExtra(PluriWaveAlarmReceiver.EXTRA_ALARM_ID, id)
                putExtra(PluriWaveAlarmReceiver.EXTRA_ALARM_TITLE, title)
            },
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )

        val showIntent = PendingIntent.getActivity(
            context,
            requestCode(id, 2),
            Intent(context, MainActivity::class.java).apply {
                flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
                putExtra(PluriWaveAlarmReceiver.EXTRA_ALARM_ID, id)
                putExtra(PluriWaveAlarmReceiver.EXTRA_ALARM_TITLE, title)
                putExtra(PluriWaveAlarmReceiver.EXTRA_ALARM_ACTION, PluriWaveAlarmReceiver.ACTION_FIRE)
            },
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )

        alarmManager.setAlarmClock(
            AlarmManager.AlarmClockInfo(triggerAtMillis, showIntent),
            alarmIntent
        )

        if (preNoticeAtMillis > System.currentTimeMillis()) {
            try {
                alarmManager.setExactAndAllowWhileIdle(
                    AlarmManager.RTC_WAKEUP,
                    preNoticeAtMillis,
                    PendingIntent.getBroadcast(
                        context,
                        requestCode(id, 3),
                        Intent(context, PluriWaveAlarmReceiver::class.java).apply {
                            action = PluriWaveAlarmReceiver.ACTION_PRE_NOTICE
                            putExtra(PluriWaveAlarmReceiver.EXTRA_ALARM_ID, id)
                            putExtra(PluriWaveAlarmReceiver.EXTRA_ALARM_TITLE, title)
                        },
                        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
                    )
                )
            } catch (_: SecurityException) {
                // The main alarm is already scheduled with setAlarmClock.
            }
        }
    }

    fun cancelAlarm(id: String) {
        for (slot in 1..3) {
            alarmManager.cancel(
                PendingIntent.getBroadcast(
                    context,
                    requestCode(id, slot),
                    Intent(context, PluriWaveAlarmReceiver::class.java),
                    PendingIntent.FLAG_NO_CREATE or PendingIntent.FLAG_IMMUTABLE
                ) ?: continue
            )
        }
        NotificationManagerCompat.from(context).cancel(
            PluriWaveAlarmReceiver.notificationIdForAlarm(id)
        )
        NotificationManagerCompat.from(context).cancel(
            PluriWaveAlarmReceiver.fireNotificationIdForAlarm(id)
        )
    }

    fun dismissFireNotification(id: String) {
        NotificationManagerCompat.from(context).cancel(
            PluriWaveAlarmReceiver.fireNotificationIdForAlarm(id)
        )
    }

    fun canScheduleExactAlarms(): Boolean {
        return Build.VERSION.SDK_INT < Build.VERSION_CODES.S ||
            alarmManager.canScheduleExactAlarms()
    }

    private fun requestCode(id: String, slot: Int): Int = 31 * id.hashCode() + slot
}
