package pt.whatsms.gateway.modules.messages

import androidx.lifecycle.LiveData
import androidx.lifecycle.distinctUntilChanged
import com.google.gson.GsonBuilder
import pt.whatsms.gateway.data.dao.MessagesDao
import pt.whatsms.gateway.data.entities.Message
import pt.whatsms.gateway.data.entities.MessageRecipient
import pt.whatsms.gateway.data.entities.MessageType
import pt.whatsms.gateway.data.entities.MessageWithRecipients
import pt.whatsms.gateway.data.entities.MessagesTotals
import pt.whatsms.gateway.domain.MessageContent
import pt.whatsms.gateway.domain.ProcessingState
import pt.whatsms.gateway.modules.messages.data.SendParams
import pt.whatsms.gateway.modules.messages.data.SendRequest
import pt.whatsms.gateway.modules.messages.data.StoredSendRequest
import java.util.Date

class MessagesRepository(private val dao: MessagesDao) {
    private val gson = GsonBuilder().serializeNulls().create()

    fun selectLast(limit: Int) = dao.selectLast(limit).distinctUntilChanged()

    val messagesTotals: LiveData<MessagesTotals> = dao.getMessagesStats().distinctUntilChanged()

    fun get(id: String): StoredSendRequest {
        return dao.get(id)?.toRequest()
            ?: throw IllegalArgumentException("Message with id $id not found")
    }

    fun enqueue(request: SendRequest): MessageWithRecipients {
        val message = MessageWithRecipients(
            Message(
                id = request.message.id,
                content = request.message.content,
                withDeliveryReport = request.params.withDeliveryReport,
                simNumber = request.params.simNumber,
                validUntil = request.params.validUntil,
                isEncrypted = request.message.isEncrypted,
                skipPhoneValidation = request.params.skipPhoneValidation,
                priority = request.params.priority ?: Message.PRIORITY_DEFAULT,
                source = request.source,

                createdAt = request.message.createdAt.time,
            ),
            request.message.phoneNumbers.map {
                MessageRecipient(
                    request.message.id,
                    it,
                    ProcessingState.Pending
                )
            },
        )

        dao.insert(message)

        return message
    }

    fun getPending(order: MessagesSettings.ProcessingOrder): StoredSendRequest? {
        while (true) {
            val message = when (order) {
                MessagesSettings.ProcessingOrder.LIFO -> dao.getPendingLifo()
                MessagesSettings.ProcessingOrder.FIFO -> dao.getPendingFifo()
            } ?: return null

            if (message.state != ProcessingState.Pending) {
                // if for some reason stored state is not in sync with recipients state
                dao.updateMessageState(message.message.id, message.state)
                continue
            }

            return message.toRequest()
        }
    }

    private fun MessageWithRecipients.toRequest(): StoredSendRequest {
        val message = this

        return StoredSendRequest(
            id = message.rowId,
            state = message.state,
            recipients = this.recipients,
            message.message.source,
            pt.whatsms.gateway.modules.messages.data.Message(
                id = message.message.id,
                content = when (message.message.type) {
                    MessageType.Text -> gson.fromJson(
                        message.message.content,
                        MessageContent.Text::class.java
                    )

                    MessageType.Data -> gson.fromJson(
                        message.message.content,
                        MessageContent.Data::class.java
                    )
                },
                phoneNumbers = message.recipients.filter { it.state == ProcessingState.Pending }
                    .map { it.phoneNumber },
                isEncrypted = message.message.isEncrypted,
                createdAt = Date(message.message.createdAt),
            ),
            SendParams(
                withDeliveryReport = message.message.withDeliveryReport,
                skipPhoneValidation = message.message.skipPhoneValidation,
                simNumber = message.message.simNumber,
                validUntil = message.message.validUntil,
                priority = message.message.priority
            ),
        )
    }
}