package ru.forbion.f7cloud.core.push

import android.Manifest
import android.content.pm.PackageManager
import android.os.Build
import android.os.PowerManager
import android.util.Log
import androidx.core.content.ContextCompat
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import ru.forbion.f7cloud.core.auth.AuthStore

class F7FirebaseMessagingService : FirebaseMessagingService() {
    override fun onNewToken(token: String) {
        Log.i(TAG, "FCM token refreshed")
        val session = AuthStore(this).load()
        if (session != null) {
            CoroutineScope(Dispatchers.IO).launch {
                val code = F7PushRegistrar.registerBlocking(this@F7FirebaseMessagingService, session, token)
                Log.i(TAG, "push register result: $code")
            }
        }
        super.onNewToken(token)
    }

    override fun onMessageReceived(message: RemoteMessage) {
        val data = message.data
        Log.i(TAG, "FCM data keys=${data.keys} priority=${message.priority}")

        val type = data["type"]
        val clickUrl = data["acceptUrl"]
            ?: data["url"]
            ?: data["clickUrl"]
            ?: data["link"]
        val priority = data["priority"]
        val highPriority = priority.equals("high", ignoreCase = true)
        val title = message.notification?.title
            ?: data["title"]
            ?: "F7cloud"
        val body = message.notification?.body
            ?: data["body"]
            ?: ""

        // Only explicit call pushes should ring — Talk recording/chat links may also contain "/call/".
        val isCall = type == "call"

        val pushEvent = F7PushEventParser.parse(data, title, body)
        F7PushEventHub.publish(pushEvent)

        if (isCall) {
            if (!canPostNotifications()) {
                Log.w(TAG, "POST_NOTIFICATIONS denied — incoming call UI blocked")
            }
            val wakeLock = (getSystemService(POWER_SERVICE) as? PowerManager)
                ?.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "f7cloud:incoming_call")
                ?.apply { acquire(30_000L) }
            try {
                val shown = F7IncomingCallQueue.enqueue(
                    context = this,
                    title = title,
                    body = body,
                    acceptUrl = data["acceptUrl"] ?: clickUrl,
                    roomToken = data["roomToken"],
                    roomDisplayName = data["roomDisplayName"],
                )
                Log.i(TAG, "Incoming call enqueued: title=$title room=${data["roomToken"]} shown=$shown")
            } catch (t: Throwable) {
                Log.e(TAG, "Incoming call notification failed", t)
            } finally {
                wakeLock?.let { if (it.isHeld) it.release() }
            }
            return
        }

        try {
            if (!canPostNotifications()) {
                Log.w(TAG, "POST_NOTIFICATIONS denied — message notification skipped")
                return
            }
            F7PushNotificationHelper.show(
                context = this,
                title = title,
                body = body,
                openUrl = clickUrl,
                highPriority = highPriority,
                type = type,
                channelHint = data["channel"],
                roomToken = data["roomToken"],
                messageId = data["messageId"],
            )
            Log.i(TAG, "Message notification shown: $title")
        } catch (t: Throwable) {
            Log.e(TAG, "Message notification failed", t)
        }
    }

    private fun canPostNotifications(): Boolean {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
            return true
        }
        return ContextCompat.checkSelfPermission(
            this,
            Manifest.permission.POST_NOTIFICATIONS,
        ) == PackageManager.PERMISSION_GRANTED
    }

    companion object {
        private const val TAG = "F7Push"
    }
}
