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

import android.content.Intent
import com.seven.ikar.kotlin.core.model.CallMediaType
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow

data class PendingIncomingCallInvite(
    val callId: String,
    val chatId: String,
    val callerId: String,
    val callerDisplayName: String,
    val callerPhoneNumber: String?,
    val mediaType: CallMediaType,
    val requestId: Long = System.nanoTime()
)

class IncomingCallInviteStore {
    private val _pendingInvite = MutableStateFlow<PendingIncomingCallInvite?>(null)
    val pendingInvite: StateFlow<PendingIncomingCallInvite?> = _pendingInvite.asStateFlow()

    fun setPending(invite: PendingIncomingCallInvite?) {
        _pendingInvite.value = invite
    }

    fun clear(requestId: Long? = null) {
        val current = _pendingInvite.value ?: return
        if (requestId == null || current.requestId == requestId) {
            _pendingInvite.value = null
        }
    }

    fun clearByCallId(callId: String?) {
        val normalizedCallId = callId?.takeIf { it.isNotBlank() } ?: return
        if (_pendingInvite.value?.callId == normalizedCallId) {
            _pendingInvite.value = null
        }
    }
}

fun PendingIncomingCallInvite.applyToIntent(intent: Intent): Intent =
    intent.apply {
        putExtra(PushDataKeys.Kind, if (mediaType == CallMediaType.Video) PushDataKinds.VideoCallInvite else PushDataKinds.AudioCallInvite)
        putExtra(PushDataKeys.CallId, callId)
        putExtra(PushDataKeys.ChatId, chatId)
        putExtra(PushDataKeys.SenderId, callerId)
        putExtra(PushDataKeys.SenderName, callerDisplayName)
        putExtra(PushDataKeys.SenderPhoneNumber, callerPhoneNumber)
        putExtra(PushDataKeys.CallMediaType, mediaType.name)
    }

fun pendingIncomingCallInviteFromMap(data: Map<String, String>): PendingIncomingCallInvite? =
    pendingIncomingCallInviteFromReader(data::get)

fun pendingIncomingCallInviteFromIntent(intent: Intent): PendingIncomingCallInvite? =
    pendingIncomingCallInviteFromReader(intent::getStringExtra)

fun endedCallIdFromMap(data: Map<String, String>): String? =
    endedCallIdFromReader(data::get)

fun endedCallIdFromIntent(intent: Intent): String? =
    endedCallIdFromReader(intent::getStringExtra)

private fun pendingIncomingCallInviteFromReader(readValue: (String) -> String?): PendingIncomingCallInvite? {
    val kind = readValue(PushDataKeys.Kind)
    if (kind != PushDataKinds.AudioCallInvite && kind != PushDataKinds.VideoCallInvite) {
        return null
    }

    val callId = readValue(PushDataKeys.CallId).orEmpty()
    val chatId = readValue(PushDataKeys.ChatId).orEmpty()
    val callerId = readValue(PushDataKeys.SenderId).orEmpty()
    val callerName = readValue(PushDataKeys.SenderName).orEmpty()
    if (callId.isBlank() || chatId.isBlank() || callerId.isBlank() || callerName.isBlank()) {
        return null
    }

    return PendingIncomingCallInvite(
        callId = callId,
        chatId = chatId,
        callerId = callerId,
        callerDisplayName = callerName,
        callerPhoneNumber = readValue(PushDataKeys.SenderPhoneNumber),
        mediaType = when {
            kind == PushDataKinds.VideoCallInvite -> CallMediaType.Video
            readValue(PushDataKeys.CallMediaType) == CallMediaType.Video.name -> CallMediaType.Video
            else -> CallMediaType.Audio
        }
    )
}

private fun endedCallIdFromReader(readValue: (String) -> String?): String? {
    val kind = readValue(PushDataKeys.Kind)
    if (kind != PushDataKinds.AudioCallEnded && kind != PushDataKinds.VideoCallEnded) {
        return null
    }

    return readValue(PushDataKeys.CallId)?.takeIf { it.isNotBlank() }
}
