package ru.forbion.f7cloud.core.push

import android.content.Context
import android.media.AudioAttributes
import android.media.MediaPlayer
import android.media.RingtoneManager
import android.util.Log

/**
 * Loops the default ringtone while an incoming call waits for Accept/Decline.
 * Debounced per call token so duplicate FCM / notification updates do not restart audio.
 */
object F7IncomingCallRinger {
    private const val TAG = "F7IncomingCallRinger"
    private const val RING_PREFS = "f7_call_ring_guard"
    private const val KEY_LAST_TOKEN = "last_token"
    private const val KEY_LAST_AT = "last_at"
    private const val RING_DEBOUNCE_MS = 90_000L

    private val lock = Any()
    private var player: MediaPlayer? = null
    private var ringing = false
    private var activeToken: String? = null

    fun isPlaying(): Boolean = synchronized(lock) {
        runCatching { player?.isPlaying == true }.getOrDefault(false)
    }

    fun shouldAlert(context: Context, callToken: String): Boolean {
        if (callToken.isBlank()) return false
        synchronized(lock) {
            if (runCatching { player?.isPlaying == true }.getOrDefault(false)) {
                return false
            }
            val prefs = context.applicationContext.getSharedPreferences(RING_PREFS, Context.MODE_PRIVATE)
            val now = System.currentTimeMillis()
            val lastToken = prefs.getString(KEY_LAST_TOKEN, "").orEmpty()
            val lastAt = prefs.getLong(KEY_LAST_AT, 0L)
            if (callToken == lastToken && now - lastAt < RING_DEBOUNCE_MS) {
                return false
            }
            prefs.edit()
                .putString(KEY_LAST_TOKEN, callToken)
                .putLong(KEY_LAST_AT, now)
                .apply()
            return true
        }
    }

    fun start(context: Context, callToken: String) {
        if (!shouldAlert(context, callToken)) {
            return
        }
        synchronized(lock) {
            ringing = true
            activeToken = callToken
            stopLocked(keepFlag = true)
            val uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)
            if (uri == null) {
                Log.w(TAG, "No default ringtone URI")
                stopLocked()
                return
            }
            val appContext = context.applicationContext
            runCatching {
                player = MediaPlayer().apply {
                    setDataSource(appContext, uri)
                    isLooping = true
                    setAudioAttributes(
                        AudioAttributes.Builder()
                            .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
                            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                            .build(),
                    )
                    setOnPreparedListener { prepared ->
                        synchronized(lock) {
                            if (!ringing) {
                                runCatching { prepared.release() }
                                return@setOnPreparedListener
                            }
                            runCatching { prepared.start() }
                                .onFailure {
                                    Log.w(TAG, "Ringtone start failed", it)
                                    stopLocked()
                                }
                        }
                    }
                    setOnErrorListener { _, what, extra ->
                        Log.w(TAG, "Ringtone error what=$what extra=$extra")
                        synchronized(lock) { stopLocked() }
                        true
                    }
                    prepareAsync()
                }
            }.onFailure {
                Log.w(TAG, "Ringtone prepare failed", it)
                stopLocked()
            }
        }
    }

    fun stop() {
        synchronized(lock) {
            stopLocked()
        }
    }

    private fun stopLocked(keepFlag: Boolean = false) {
        if (!keepFlag) {
            ringing = false
            activeToken = null
        }
        player?.runCatching {
            if (isPlaying) stop()
            release()
        }
        player = null
    }
}
