package com.adealink.weparty.room.sdk.controller.impl

import android.os.Handler
import com.adealink.frame.base.CommonDataNullError
import com.adealink.frame.base.IError
import com.adealink.frame.base.Rlt
import com.adealink.frame.ext.safeSubList
import com.adealink.frame.log.Log
import com.adealink.frame.room.data.FlowStateInfo
import com.adealink.weparty.module.room.chat.data.MESSAGE_TYPE
import com.adealink.weparty.module.room.chat.data.MESSAGE_TYPE_TEXT
import com.adealink.weparty.module.room.chat.data.Message
import com.adealink.weparty.module.room.chat.data.Notification
import com.adealink.weparty.module.room.chat.data.toMessages
import com.adealink.weparty.module.room.chat.data.toNotifications
import com.adealink.weparty.room.sdk.context.IRoomContext
import com.adealink.weparty.room.sdk.controller.BaseController
import com.adealink.weparty.room.sdk.controller.IMessageController
import com.adealink.weparty.room.sdk.listener.IMessageListener
import com.adealink.weparty.room.sdk.service.roomService
import io.trtc.tuikit.atomicxcore.api.CompletionHandler
import io.trtc.tuikit.atomicxcore.api.barrage.Barrage
import io.trtc.tuikit.atomicxcore.api.barrage.BarrageStore
import io.trtc.tuikit.atomicxcore.api.barrage.BarrageType
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume

class MessageController(override val ctx: IRoomContext, serialHandler: Handler) :
    BaseController<IMessageListener>(ctx, serialHandler),
    IMessageController<IMessageListener> {

    private var barrageStore: BarrageStore? = null

    private var messageListJob: Job? = null

    override fun onRoomIn(flowStateInfo: FlowStateInfo) {
        super.onRoomIn(flowStateInfo)
        barrageStore = BarrageStore.create(flowStateInfo.roomId)
        subscribeToBarrageUpdates()
    }

    override fun onRoomLeaved(flowStateInfo: FlowStateInfo) {
        super.onRoomLeaved(flowStateInfo)
        messageListJob?.cancel()
    }

    // 对外暴露【全量】消息列表的Flow，方便UI层订阅
    private val _messagesFlow = MutableStateFlow<List<Message>>(emptyList())
    override val messagesFlow: StateFlow<List<Message>> = _messagesFlow.asStateFlow()

    private val _newMessagesFlow = MutableStateFlow<List<Message>>(emptyList())
    override val newMessagesFlow: StateFlow<List<Message>> = _newMessagesFlow.asStateFlow()

    private val _oldNotificationFlow = MutableStateFlow<List<Notification>>(emptyList())
    private val _notificationFlow = MutableStateFlow<List<Notification>>(emptyList())
    override val notificationsFlow: StateFlow<List<Notification>> = _notificationFlow.asStateFlow()

    private fun subscribeToBarrageUpdates() {
        messageListJob = launch {
            barrageStore?.barrageState?.messageList?.collect { allMessages ->
                val roomId = roomService.joinController.getJoinedRoomId() ?: return@collect
                val textMessages = allMessages.filter { it.liveID == roomId && it.messageType == BarrageType.TEXT }.toMessages()
                handleTextMessage(textMessages)

                val notifications = allMessages.filter { it.liveID == roomId && it.messageType == BarrageType.CUSTOM }.toNotifications()
                handleNotifications(notifications)
            }
        }
    }

    private fun handleTextMessage(messages: List<Message>) {
        val oldMessages = _messagesFlow.value
        val lastMessage = oldMessages.lastOrNull()
        if (lastMessage != null) {
            val lastIndex = messages.indexOfLast { it.barrage.sequence == lastMessage.barrage.sequence }
            val newMessages = messages.safeSubList(lastIndex + 1)
            _newMessagesFlow.value = newMessages
        } else {
            _newMessagesFlow.value = messages
        }

        _messagesFlow.value = messages
    }

    private fun handleNotifications(notifications: List<Notification>) {
        val oldNotifications = _oldNotificationFlow.value
        val lastNotification = oldNotifications.lastOrNull()
        if (lastNotification != null) {
            val lastIndex = notifications.indexOfLast { it.barrage.sequence == lastNotification.barrage.sequence }
            val newNotifications = notifications.safeSubList(lastIndex + 1)
            _notificationFlow.value = newNotifications
        } else {
            _notificationFlow.value = notifications
        }

        _oldNotificationFlow.value = notifications
    }

    override suspend fun sendTextMessage(text: String): Rlt<Any> {
        return suspendCancellableCoroutine { continuation ->
            val barrage = barrageStore
            if (barrage == null) {
                if (continuation.isActive) {
                    continuation.resume(Rlt.Failed(CommonDataNullError()))
                }
                return@suspendCancellableCoroutine
            }
            barrage.sendTextMessage(
                text, mapOf(
                    MESSAGE_TYPE to MESSAGE_TYPE_TEXT
                ), object : CompletionHandler {
                    override fun onFailure(code: Int, desc: String) {
                        if (continuation.isActive) {
                            continuation.resume(Rlt.Failed(IError(serverCode = code, msg = desc)))
                        }
                    }

                    override fun onSuccess() {
                        if (continuation.isActive) {
                            continuation.resume(Rlt.Success(Unit))
                        }
                    }
                })
        }
    }

    override suspend fun sendLocalMessage(barrage: Barrage): Rlt<Any> {
        return suspendCancellableCoroutine { continuation ->
            val barrageStore = barrageStore
            if (barrageStore == null) {
                if (continuation.isActive) {
                    continuation.resume(Rlt.Failed(CommonDataNullError()))
                }
                return@suspendCancellableCoroutine
            }

            barrageStore.appendLocalTip(barrage.apply {
                liveID = roomService.joinController.getJoinedRoomId() ?: ""
            })
            continuation.resume(Rlt.Success(Any()))
        }
    }

}
