package es.verdnatura.presentation.view.feature.login.fragment

import android.content.Context
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.map
import com.google.gson.Gson
import com.google.gson.JsonObject
import com.google.gson.reflect.TypeToken
import es.verdnatura.MobileApplication
import es.verdnatura.domain.ConstAndValues.TOKEN
import es.verdnatura.domain.ConstAndValues.TOKENCREATED
import es.verdnatura.domain.ConstAndValues.TTL
import es.verdnatura.domain.SalixCallback
import es.verdnatura.domain.formatWithQuotes
import es.verdnatura.presentation.base.BaseViewModel
import es.verdnatura.presentation.base.getMessageFromAllResponse
import es.verdnatura.presentation.base.nameofFunction
import es.verdnatura.presentation.common.Event
import es.verdnatura.presentation.view.feature.historicoshelvinglog.model.DeviceLogSalix
import es.verdnatura.presentation.view.feature.login.model.AccessConfigSalix
import es.verdnatura.presentation.view.feature.login.model.AccessConfigSalixList
import es.verdnatura.presentation.view.feature.login.model.DataUserSalix
import es.verdnatura.presentation.view.feature.login.model.LoginDevice
import es.verdnatura.presentation.view.feature.login.model.LoginSalixVO
import es.verdnatura.presentation.view.feature.login.model.OperatorAdd
import es.verdnatura.presentation.view.feature.login.model.OperatorSalix
import es.verdnatura.presentation.view.feature.login.model.RenewToken
import es.verdnatura.presentation.view.feature.login.model.VersionApp
import es.verdnatura.presentation.view.feature.login.model.WorkerData
import es.verdnatura.presentation.view.feature.paletizador.model.ItemsExpeditionDynamics
import kotlinx.coroutines.runBlocking
import retrofit2.Response
import java.util.Date

class LoginViewModel(val context: Context) : BaseViewModel(context) {

    private val _loginSalixItem by lazy { MutableLiveData<LoginSalixVO>() }
    val loginSalixItem: LiveData<LoginSalixVO>
        get() = _loginSalixItem

    private val _handleUserResponse by lazy { MutableLiveData<WorkerData>() }
    val handleUserResponse: LiveData<WorkerData> = _handleUserResponse

    private val _serialNumber by lazy { MutableLiveData<String?>() }
    val serialNumber: LiveData<String?> = _serialNumber

    private val _versionAppItem by lazy { MutableLiveData<VersionApp>() }
    val versionAppItem: LiveData<VersionApp>
        get() = _versionAppItem

    private val _logindevice by lazy { MutableLiveData<LoginDevice>() }
    val logindevice: LiveData<LoginDevice>
        get() = _logindevice

    private val _workerOperator by lazy { MutableLiveData<OperatorSalix>() }
    val workerOperator: LiveData<OperatorSalix>
        get() = _workerOperator

    private val _accessConfigSalixList by lazy { MutableLiveData<AccessConfigSalixList>() }

    private val _renewTokenResponse by lazy { MutableLiveData<RenewToken>() }
    val renewTokenResponse: LiveData<RenewToken>
        get() = _renewTokenResponse
    val loadAccessConfigSalixList: LiveData<Event<AccessConfigSalixList>> =
        _accessConfigSalixList.map { Event(it) }

    fun loginSalix(user: String, password: String) {
        salix.login(LoginSalixVO(user, password))
            .enqueue(object : SalixCallback<LoginSalixVO>(context) {
                override fun onSuccess(response: Response<LoginSalixVO>) {

                    _loginSalixItem.value = response.body()?.let {
                        LoginSalixVO(
                            user,
                            password,
                            it.token,
                            it.created,
                            it.ttl,
                            isError = false,
                            errorMessage = ""
                        )
                    }

                }

                override fun onError(t: Throwable) {
                    _loginSalixItem.value = LoginSalixVO(
                        user,
                        password,
                        "",
                        isError = true,
                        errorMessage = getMessageFromAllResponse(
                            nameofFunction(this), t.message!!
                        )
                    )
                }
            })
    }

    fun validateAuth(user: String, password: String, code: String) {
        salix.validateAuth(user, password, code)
            .enqueue(object : SalixCallback<LoginSalixVO>(context) {
                override fun onSuccess(response: Response<LoginSalixVO>) {

                    _loginSalixItem.value = response.body()?.let {
                        LoginSalixVO(
                            user,
                            password,
                            it.token,
                            it.created,
                            it.ttl,
                            isError = false,
                            errorMessage = ""
                        )

                    }

                }

                override fun onError(t: Throwable) {
                    _loginSalixItem.value = LoginSalixVO(
                        user,
                        password,
                        "",
                        isError = true,
                        errorMessage = getMessageFromAllResponse(
                            nameofFunction(this), t.message!!
                        )
                    )
                }
            })
    }

    fun handleUser(
        login: MutableMap<String, Any>
    ) {
        salix.handleUser(login).enqueue(object : SalixCallback<WorkerData>(context) {
            override fun onSuccess(response: Response<WorkerData>) {
                app.userName = response.body()?.nickname
                app.userId = response.body()?.id
                app.serialNumber = response.body()?.serialNumber
                _handleUserResponse.value = response.body()
            }

        })
    }

    fun deviceCheckLogin(userId: Int, androidId: String) {

        salix.deviceCheckLogin(arrayListOf(userId, androidId).formatWithQuotes())
            .enqueue(object : SalixCallback<List<LoginDevice>>(context) {
                override fun onSuccess(response: Response<List<LoginDevice>>) {
                    response.body()?.get(0).let {
                        _logindevice.value = LoginDevice(
                            it!!.vMessage, it.vIsAuthorized
                        )
                    }

                }
            })
    }

    fun getCurrentUserData(
        appName: String, versionApp: String, androidId: String, serialNumber: String? = null
    ) {
        salix.getCurrentUserData().enqueue(object : SalixCallback<DataUserSalix>(context) {
            override fun onSuccess(response: Response<DataUserSalix>) {
                app.userName = response.body()?.nickname
                app.userId = response.body()?.id
                deviceLogAddSalix(
                    app = appName,
                    versionApp = versionApp,
                    androidId = androidId,
                    userFk = app.userId!!,
                    serialnumber = serialNumber
                )
                //Tarea 5870
                operatorAdd(app.userId)
                operatorGetData(app.userId!!)
                deviceCheckLogin(app.userId!!, androidId)
            }
        })
    }

    fun getSerialNumber(
        device: Int
    ) {
        salix.getSerialNumber("""{"where":{"id":$device},"fields":"serialNumber"}""")
            .enqueue(object : SalixCallback<List<JsonObject>>(context) {
                override fun onSuccess(response: Response<List<JsonObject>>) {

                    _serialNumber.value =
                        response.body()?.firstOrNull()?.get("serialNumber")?.asString
                }
            })
    }

    fun deviceLogAddSalix(
        app: String, versionApp: String, androidId: String, userFk: Int, serialnumber: String?
    ) {

        //Tarea 4815
        salix.deviceLogInsert(
            DeviceLogSalix(
                android_id = androidId,
                userFk = userFk,
                nameApp = app,
                versionApp = versionApp,
                serialNumber = serialnumber
            )
        ).enqueue(object : SalixCallback<Unit>(context) {})

    }

    fun checkVersion(nameApp: String) {
        salix.getVersion(nameApp).enqueue(object : SalixCallback<VersionApp>(context) {
            override fun onSuccess(response: Response<VersionApp>) {

                _versionAppItem.value = response.body()?.let {
                    VersionApp(
                        it.appname,
                        it.version,
                        it.isVersionCritical,
                        it.url,
                    )

                }

            }
        })
    }

    fun getListFromJSON(json: JsonObject): MutableList<ItemsExpeditionDynamics> {
        val gson = Gson()
        val list = mutableListOf<ItemsExpeditionDynamics>()
        val expeditionState: Map<String, Any> =
            gson.fromJson(json, object : TypeToken<Map<String, Any>>() {}.type)
        expeditionState.forEach {

            list.add(ItemsExpeditionDynamics(key = it.key, value = it.value.toString()))

        }
        return list
    }

    fun operatorAdd(workerFk: Int? = null) {
        salix.operatorAdd(OperatorAdd(workerFk!!, false))
            .enqueue(object : SalixCallback<Any>(context) {
                override fun onError(t: Throwable) {

                    if (!(t.message!!.contains("ER_DUP_ENTRY"))) onError(t)
                }

            })
    }

    fun operatorGetData(
        workerId: Int
    ) {
        val filter =
            """{"fields":["itemPackingTypeFk","numberOfWagons","sectorFk","trainFk","labelerFk","isOnReservationMode"],"include":[{"relation":"sector","scope":{"fields":["description","warehouseFk"]}},{"relation":"printer","scope":{"fields":["name"]}},{"relation":"train","scope":{"fields":["name"]}}]}"""
        salix.operatorGetData(id = workerId, filter)
            .enqueue(object : SalixCallback<OperatorSalix>(context) {

                override fun onSuccess(response: Response<OperatorSalix>) {
                    _workerOperator.value = response.body()
                }

            })
    }

    fun getAccessTokenConfigs(
    ) {

        salix.getAccessTokenConfigs()
            .enqueue(object : SalixCallback<List<AccessConfigSalix>>(context) {

                override fun onSuccess(response: Response<List<AccessConfigSalix>>) {
                    _accessConfigSalixList.value = response.body()?.let {
                        AccessConfigSalixList(it)
                    }
                }

            })
    }

    fun renewToken(
    ) {
        salix.renewToken().enqueue(object : SalixCallback<RenewToken>(context) {

            override fun onSuccess(response: Response<RenewToken>) {

                val renewToken = response.body()
                runBlocking {
                    (context as MobileApplication).dataStoreApp.editDataStoreKey(
                        TOKEN, renewToken!!.id
                    )
                    (context).dataStoreApp.editDataStoreKey(
                        TTL, renewToken.ttl
                    )
                    (context).dataStoreApp.editDataStoreKey(
                        TOKENCREATED, Date().time
                    )
                }

                _renewTokenResponse.value = renewToken

            }

            override fun onError(t: Throwable) {

                _renewTokenResponse.value = RenewToken(
                    "", 0, true, getMessageFromAllResponse(
                        nameofFunction(this), t.message!!
                    )
                )

            }

        })
    }
}
