package dev.meloda.fast.messageshistory

import android.util.Log
import com.conena.nanokt.collections.indexOfFirstOrNull
import dev.meloda.fast.common.extensions.setValue
import dev.meloda.fast.messageshistory.model.MessagesHistoryScreenState
import dev.meloda.fast.model.LongPollParsedEvent
import dev.meloda.fast.model.api.domain.VkMessage
import kotlinx.coroutines.flow.MutableStateFlow
import kotlin.math.abs

internal class MessagesHistoryLongPollEventHandler(
    private val screenState: MutableStateFlow<MessagesHistoryScreenState>,
    private val messages: MutableStateFlow<List<VkMessage>>,
    private val syncUiMessages: () -> Unit
) {
    fun onNewMessage(event: LongPollParsedEvent.NewMessage) {
        val message = event.message

        Log.d("MessagesHistoryViewModel", "handleNewMessage: $message")

        if (message.peerId != screenState.value.convoId) return
        if (messages.value.indexOfFirstOrNull { it.id == message.id } != null) return

        val randomIds = messages.value.map(VkMessage::randomId)
        if (message.randomId != 0L && message.randomId in randomIds) return

        val newMessages = messages.value.toMutableList()
        newMessages.add(0, message)

        messages.setValue { newMessages }
        syncUiMessages()
    }

    fun onMessageEdited(event: LongPollParsedEvent.MessageEdited) {
        val message = event.message
        if (message.peerId != screenState.value.convoId) return

        val newMessages = messages.value.toMutableList()
        val index = newMessages.indexOfFirstOrNull { it.id == message.id }
        if (index == null) {
            return
        }

        newMessages[index] = message
        messages.setValue { newMessages }
        syncUiMessages()
    }

    fun onReadIncoming(event: LongPollParsedEvent.IncomingMessageRead) {
        if (event.peerId != screenState.value.convoId) return

        val index = messages.value.indexOfFirstOrNull { it.cmId == event.cmId }
        if (index == null) return

        val newConvo = screenState.value.convo.copy(
            inReadCmId = event.cmId
        )

        screenState.setValue { old ->
            old.copy(convo = newConvo)
        }

        syncUiMessages()
    }

    fun onReadOutgoing(event: LongPollParsedEvent.OutgoingMessageRead) {
        if (event.peerId != screenState.value.convoId) return

        val index = messages.value.indexOfFirstOrNull { it.cmId == event.cmId }
        if (index == null) return

        val newConvo = screenState.value.convo.copy(
            outReadCmId = event.cmId
        )

        screenState.setValue { old ->
            old.copy(convo = newConvo)
        }

        syncUiMessages()
    }

    fun onMessageDeleted(event: LongPollParsedEvent.MessageDeleted) {
        if (event.peerId != screenState.value.convoId) return

        val newMessages = messages.value.toMutableList()
        val index = newMessages.indexOfFirstOrNull { it.cmId == event.cmId }
        if (index == null) return

        newMessages.removeAt(index)
        messages.setValue { newMessages }
        syncUiMessages()
    }

    fun onMessageRestored(event: LongPollParsedEvent.MessageRestored) {
        if (event.message.peerId != screenState.value.convoId) return

        val newMessages = messages.value.toMutableList()
        val minDate = newMessages.minOf(VkMessage::date)

        if (event.message.date < minDate) return

        newMessages.add(event.message)
        messages.setValue { newMessages.sorted() }
        syncUiMessages()
    }

    fun onMessageMarkedAsImportant(event: LongPollParsedEvent.MessageMarkedAsImportant) {
        if (event.peerId != screenState.value.convoId) return

        val newMessages = messages.value.toMutableList()
        val index = newMessages.indexOfFirstOrNull { it.cmId == event.cmId }
        if (index == null) return

        newMessages[index] = newMessages[index].copy(isImportant = event.marked)
        messages.setValue { newMessages }
        syncUiMessages()
    }

    fun onMessageMarkedAsSpam(event: LongPollParsedEvent.MessageMarkedAsSpam) {
        if (event.peerId != screenState.value.convoId) return

        val newMessages = messages.value.toMutableList()
        val index = newMessages.indexOfFirstOrNull { it.cmId == event.cmId }
        if (index == null) return

        newMessages.removeAt(index)
        messages.setValue { newMessages }
        syncUiMessages()
    }

    fun onMessageMarkedAsNotSpam(event: LongPollParsedEvent.MessageMarkedAsNotSpam) {
        if (event.message.peerId != screenState.value.convoId) return

        val newMessages = messages.value.toMutableList()
        val maxDate = newMessages.maxOf(VkMessage::date)
        val minDate = newMessages.minOf(VkMessage::date)

        if (event.message.date !in minDate..maxDate) return

        newMessages.add(event.message)
        messages.setValue { newMessages.sorted() }
        syncUiMessages()
    }

    private fun List<VkMessage>.sorted(): List<VkMessage> {
        return sortedWith { m1, m2 ->
            val dateDiff = m2.date - m1.date
            if (dateDiff != 0) {
                dateDiff
            } else {
                val idDiff = m2.id - m1.id
                idDiff.toInt()
            }
        }
    }
}
