package com.seven.ikar.kotlin.core.push

import android.content.Context
import android.media.AudioAttributes
import android.media.Ringtone
import android.media.RingtoneManager
import android.net.Uri
import android.os.SystemClock

object AndroidMessageNotificationSound {
    private const val DuplicateSuppressionWindowMs = 5000L
    private const val MinimumGapBetweenSoundsMs = 2000L
    private val playbackLock = Any()
    private var lastPlayedKey: String? = null
    private var lastPlayedAtMs: Long = 0L
    private var activeRingtone: Ringtone? = null

    fun resolveUri(option: NotificationSoundOption): Uri? = when (option) {
        NotificationSoundOption.Default -> RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
        NotificationSoundOption.Ringtone -> RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)
        NotificationSoundOption.Alarm -> RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM)
        NotificationSoundOption.Silent -> null
    }

    fun resolveAudioAttributes(option: NotificationSoundOption): AudioAttributes? = when (option) {
        NotificationSoundOption.Default -> notificationAudioAttributes(AudioAttributes.USAGE_NOTIFICATION)
        NotificationSoundOption.Ringtone -> notificationAudioAttributes(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
        NotificationSoundOption.Alarm -> notificationAudioAttributes(AudioAttributes.USAGE_ALARM)
        NotificationSoundOption.Silent -> null
    }

    fun play(context: Context, option: NotificationSoundOption, dedupeKey: String? = null) {
        val soundUri = resolveUri(option) ?: return
        val audioAttributes = resolveAudioAttributes(option) ?: return
        val now = SystemClock.elapsedRealtime()
        synchronized(playbackLock) {
            if (now - lastPlayedAtMs < MinimumGapBetweenSoundsMs) {
                return
            }
            if (dedupeKey != null && dedupeKey == lastPlayedKey && now - lastPlayedAtMs < DuplicateSuppressionWindowMs) {
                return
            }

            runCatching {
                activeRingtone?.stop()
                RingtoneManager.getRingtone(context.applicationContext, soundUri)?.apply {
                    this.audioAttributes = audioAttributes
                    play()
                    activeRingtone = this
                }
            }
            lastPlayedKey = dedupeKey
            lastPlayedAtMs = now
        }
    }

    private fun notificationAudioAttributes(usage: Int): AudioAttributes =
        AudioAttributes.Builder()
            .setUsage(usage)
            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
            .build()
}
