package io.nexilis.service.data.repositories

import android.content.Context
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.lifecycle.LiveData
import androidx.paging.PagingSource
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.OutOfQuotaPolicy
import androidx.work.WorkManager
import androidx.work.WorkRequest
import androidx.work.workDataOf
import io.nexilis.service.apiScope
import io.nexilis.service.core.Outgoing
import io.nexilis.service.data.daos.GroupMemberDao
import io.nexilis.service.data.daos.MessageDao
import io.nexilis.service.data.daos.MessageStatusDao
import io.nexilis.service.data.entities.MainEntity
import io.nexilis.service.data.entities.Message
import io.nexilis.service.data.entities.MessageStatus
import io.nexilis.service.tag
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.UUID
import javax.inject.Inject


class MessageRepository @Inject constructor(
    private val dao: MessageDao,
    private val messageStatusDao: MessageStatusDao,
    private val groupMemberDao: GroupMemberDao,
) : Repository {

    val all: LiveData<List<Message>> = dao.getAll()

    fun get(id: String): LiveData<Message> {
        return dao.get(id)
    }
    fun getOpposite(pin: String, offset: Int = -1, limit: Int = -1): PagingSource<Int, Message> {
        return dao.getOpposite(pin, offset, limit)
    }

    override suspend fun insert(entity: MainEntity) {
        dao.insert(entity as Message)
    }

    suspend fun send(
        context: Context,
        entity: MainEntity
    ) {
        val message = entity as Message
        dao.insert(message)
        if (message.message_scope_id == "4") {
            val id = message.chat_id.ifEmpty { message.l_pin }
            groupMemberDao.getSync(id)?.let {
                it.forEach { member ->
                    messageStatusDao.insert(
                        MessageStatus(
                            message_id = message.message_id,
                            f_pin = member.f_pin,
                            user_id = member.f_pin,
                            last_update = System.currentTimeMillis(),
                            time_delivered = 0,
                            time_read = 0,
                            time_ack = 0,
                        )
                    )
                }
            }
        } else {
            messageStatusDao.insert(
                MessageStatus(
                    message_id = message.message_id,
                    f_pin = message.opposite_pin,
                    user_id = message.opposite_pin,
                    last_update = System.currentTimeMillis(),
                    time_delivered = 0,
                    time_read = 0,
                    time_ack = 0,
                )
            )
        }
        Log.d("SAPI", "WorkManager:enqueue:${message.message_id}")
        val id = UUID.randomUUID()
        val workRequest: WorkRequest =
            OneTimeWorkRequestBuilder<Outgoing>()
                .setId(id)
                .setInputData(
                    workDataOf(
                        "data" to message.message_id
                    )
                )
                .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
                .build()
        WorkManager.getInstance(context).enqueue(workRequest)
        withContext(Dispatchers.Main) {
            WorkManager.getInstance(context).getWorkInfoByIdLiveData(id)
                .observe(context as ComponentActivity) { workInfo ->
                    if (workInfo.state.isFinished) {
                        val messageId = workInfo.outputData.getString("message_id") ?: ""
                        val pin = workInfo.outputData.getString("opposite_pin") ?: ""
                        val status = workInfo.outputData.getInt("status", 0)
                        Log.d(
                            tag,
                            "update from work:$messageId:$pin:$status"
                        )
                        apiScope.launch(Dispatchers.IO) {
                            if (messageId.isNotEmpty()) {
                                messageStatusDao.updateStatus(
                                    status,
                                    messageId = messageId,
                                    pin = pin
                                )
                            }
                        }
                    }
                }
        }
    }
}