package com.khmer9.lotto.app

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.khmer9.lotto.base.BaseViewModel
import com.khmer9.lotto.extension.prepend
import com.khmer9.lotto.remote.*
import com.khmer9.lotto.remote.service.EventListener
import com.khmer9.lotto.remote.service.ApiService
import com.khmer9.lotto.remote.service.ConnectivityStates
import com.khmer9.lotto.remote.service.SocketService
import com.khmer9.lotto.screen.report.ReportViewState
import com.khmer9.lotto.screen.result.ResultViewState
import com.khmer9.lotto.util.Event
import com.khmer9.lotto.util.PrefHelper
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import org.json.JSONObject
import java.net.URISyntaxException
import java.util.concurrent.TimeUnit

class ShareViewModel(
    private val apiService: ApiService,
    private val prefHelper: PrefHelper,
    private val socketService: SocketService
) : BaseViewModel(), EventListener {
    //Socket Data LiveData
    private val newMessagesLotto = MutableLiveData<SocketMessageDataModel>()
    val getLottoMessage: LiveData<SocketMessageDataModel> get() = newMessagesLotto

    //Socket Data LiveData
    private val newCreatedBetting = MutableLiveData<JSONObject>()
    val getBettingCreated: LiveData<JSONObject> get() = newCreatedBetting

    //Socket Connection Live Data
    private val connectivityStateLD = MutableLiveData<Int>()
    val getConnectivityStates: LiveData<Int> get() = connectivityStateLD
    //MainScreen and Create Betting Screen
    private val shareState = MutableLiveData<ShareViewState>(ShareViewState())
    val getShareState: LiveData<ShareViewState> = shareState

    //Result Screen Live Data
    private val resultState = MutableLiveData<ResultViewState>(ResultViewState())
    val getResultState: LiveData<ResultViewState> = resultState

    //Report Screen Live Data
    private val reportState = MutableLiveData<ReportViewState>(ReportViewState())
    val getReportState: LiveData<ReportViewState> = reportState

//    val isCallAPI = MutableLiveData<Boolean>()
//    fun setIsCall(isCall: Boolean) {
//        isCallAPI.postValue(isCall)
//    }

    fun remoteReport(userId: String){
        if (reportState.value!!.isProgress) return
        reportState.value = prevReport().copy(isProgress = true)
        //val user = ModelPreferencesManager.get<User>("USER")

        disposables.add(
            apiService.remoteReportScreen(userId = userId)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({response->
                    if (response.resultCode == "1") {
                        response.data?.let {

                            reportState.value = prevReport().copy(
                                isProgress = false,
                                winList = it.winList,
                                winLostList = it.winLostLst,
                                statementList = it.statementList,
                                error = null

                            )

                        }

                    } else {
                        reportState.value = prevReport().copy(isProgress = false, error = "[${response.message.description}]")
                    }

                },{
                    val message : String ="ប្រតិបត្តិការមិនជោគជ័យ\n"+it.getErrorCode()
                    reportState.value = prevReport().copy(isProgress = false, error = message)

                })
        )



    }
    fun remoteResult(){

        if (resultState.value!!.isProgress) return
        resultState.value = prevResult().copy(isProgress = true)
        disposables.add(
            apiService.remoteResultScreen()
                .timeout(60, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({response->
                    if (response.resultCode == "1") {
                        response.data?.let {


//                           val sortedList : MutableList<com.sambath.lotto.remote.Result> = mutableListOf(
//                               Result("1","","","","","","Large","","","","1",""),
//                               Result("2","","","","","","Large","","","","1","") ,
//                               Result("3","","","","","","Small","","","","1",""),
//                               Result("4","","","","","","Small","","","","5","") ,
//                               Result("5","","","","","","Small","","","","1","") ,
//                               Result("6","","","","","","Small","","","","1","") ,
//                               Result("7","","","","","","Small","","","","1","") ,
//                               Result("8","","","","","","Small","","","","1","") ,
//                               Result("9","","","","","","Small","","","","2","") ,
//                               Result("10","","","","","","Large","","","","2","") ,
//                               Result("11","","","","","","Small","","","","2","") ,
//                               Result("12","","","","","","Small","","","","2","") ,
//                               Result("13","","","","","","Large","","","","2","") ,
//
//
//                               )


                            val sortedList = it.resultList?.sortedWith(compareBy { it.no})
                            resultState.value = prevResult().copy(
                                isProgress = false,
                                resultList = sortedList,
                                error = null


                            )


                        }

                    } else {
                        resultState.value = prevResult().copy(isProgress = false, error = "[${response.message.description}]")
                    }

                },{
                    val message : String ="ប្រតិបត្តិការមិនជោគជ័យ\n"+it.getErrorCode()
                    resultState.value = prevResult().copy(isProgress = false, error = message)

                })
        )



    }

    fun addOtherCreatedBetting(accountBalance: String, currentBetting: CurrentBetting?){
        currentBetting?.let {
            var newList = shareState.value?.myBettingList

            if (newList.isNullOrEmpty()){
                newList = mutableListOf(ListItem(id = it.id, setId=it.setId, typeOfBetting = it.typeOfBetting, category = it.category, user_id = it.userId, date = it.date, amount = it.amount, cast = it.cast, win_lose = null, amount_win = "0"))

            }else {
                if (shareState.value!!.myBettingId == it.no){
                    newList.prepend(ListItem(id = it.id, setId=it.setId, typeOfBetting = it.typeOfBetting, category = it.category, user_id = it.userId, date = it.date, amount = it.amount, cast = it.cast, win_lose = null, amount_win = "0"))
                }else newList = mutableListOf(ListItem(id = it.id, setId=it.setId, typeOfBetting = it.typeOfBetting, category = it.category, user_id = it.userId, date = it.date, amount = it.amount, cast = it.cast, win_lose = null, amount_win = "0"))


            }
            shareState.value = prevShare().copy(
                myBettingId = it.no,
                myBettingList = newList,
                accountBalance = accountBalance,
                isAutoPrint= null,

                )
        }

    }


    fun remoteCreateBettingAPI(lottoSet: LottoSet, amount: Int, userId: String){

        if (shareState.value!!.isProgress) return

        val request = PlayRequest(setID = lottoSet.id,userId =userId, no = shareState.value!!.nextNo!!,cast = lottoSet.payment,amount = amount )

        shareState.value = prevShare().copy(
            initial = false,
            isProgress = true,
            error = null,
            isAutoPrint = null
        )

        disposables.add(
            apiService.createBetting(request)
                .timeout(20, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({response->
                    if (response.resultCode == "1") {
                        response.data?.let {playData->

                            playData.myBetting?.let {
                                var newList = shareState.value?.myBettingList

                                if (newList.isNullOrEmpty()){
                                    newList = mutableListOf(ListItem(id = it.id, setId=it.setId, typeOfBetting = it.typeOfBetting, category = it.category, user_id = it.userId, date = it.date, amount = it.amount, cast = it.cast, win_lose = it.win_lose, amount_win = "0"))

                                }else {
                                    if (shareState.value!!.myBettingId == it.no){
                                        newList.prepend(ListItem(id = it.id, setId=it.setId, typeOfBetting = it.typeOfBetting, category = it.category, user_id = it.userId, date = it.date, amount = it.amount, cast = it.cast, win_lose = it.win_lose, amount_win = "0"))
                                    }else newList = mutableListOf(ListItem(id = it.id, setId=it.setId, typeOfBetting = it.typeOfBetting, category = it.category, user_id = it.userId, date = it.date, amount = it.amount, cast = it.cast, win_lose = it.win_lose, amount_win = "0"))


                                }

                                shareState.value = prevShare().copy(
                                    isProgress = false,
                                    myBettingId = it.no,
                                    myBettingList = newList,
                                    currentBetting = it,
                                    accountBalance = playData.accountBalance,
                                    error = null,
                                    isAutoPrint = Event(prefHelper.getIsAutoPrint())

                                )

                            }

                        }

                    } else {
                        shareState.value = prevShare().copy(isProgress = false, error = "[${response.message.description}]")
                    }

                },{
                    val message : String ="ប្រតិបត្តិការមិនជោគជ័យ\n"+it.getErrorCode()
                    shareState.value = prevShare().copy(isProgress = false, error = message)

                })
        )

    }

    fun remoteMainScreenAPI(userId: String){

        if (shareState.value!!.isProgress) return
        shareState.value = prevShare().copy(
            initial = false,
            isProgress = true,
            error = null,
            myBettingId = null,
            myBettingList = null,
            result = null,
            accountBalance = null,
            nextNo = null,
        )

        disposables.add(
            apiService.remoteMainScreen(userId)
                .timeout(60, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({response->
                    if (response.resultCode == "1") {
                        response.data?.let {
                            shareState.value = prevShare().copy(
                                isProgress = false,
                                myBettingId = it.myBetting?.id,
                                myBettingList = it.myBetting?.data as MutableList<ListItem>?,
                                accountBalance = it.accountBalance,
                                nextNo = it.nextNo,
                                result = it.result,
                                error = null
                            )
                        }

                    } else {
                        shareState.value = prevShare().copy(isProgress = false, error = "[${response.message.description}]")
                    }

                },{
                    val message : String ="ប្រតិបត្តិការមិនជោគជ័យ\n"+it.getErrorCode()
                    shareState.value = prevShare().copy(isProgress = false, error = message)

                })
        )

    }

    // Remote
    fun startListeningToSocketServer(userId: String) {
        //if(prefHelper.getToken().isEmpty()) return
        try {
            //val jsonObjectLottoRoom = JSONObject()
           // jsonObjectLottoRoom.put("_id", "group-loto-betting")

            val jsonObjectBettingRoom = JSONObject()
            jsonObjectBettingRoom.put("_id", "group-loto-betting")
            jsonObjectBettingRoom.put("user_id",userId)
            socketService.registerListener(this)
            socketService.startListening(jsonObjectBettingRoom)
        } catch (e: URISyntaxException) {
            e.printStackTrace()
        }
    }

    fun emitCreateBetting(userId : String, accountBalances: String, objCurrentBetting: CurrentBetting){
        try {
            val jsonObject = JSONObject()
            val jsonCurrentBetting = JSONObject()
            jsonCurrentBetting.put("_id",objCurrentBetting.id)
            jsonCurrentBetting.put("no",objCurrentBetting.no)
            jsonCurrentBetting.put("set_result_id",objCurrentBetting.setId)
            jsonCurrentBetting.put("type_of_betting",objCurrentBetting.typeOfBetting)
            jsonCurrentBetting.put("category",objCurrentBetting.category)
            jsonCurrentBetting.put("user_id",objCurrentBetting.userId)
            jsonCurrentBetting.put("date",objCurrentBetting.date)
            jsonCurrentBetting.put("amount",objCurrentBetting.amount)
            jsonCurrentBetting.put("cast",objCurrentBetting.cast)
            jsonCurrentBetting.put("win_lose",objCurrentBetting.win_lose)
            jsonCurrentBetting.put("amount_win",objCurrentBetting.amount_win)
            jsonObject.put("_id", "group-loto-betting")
            jsonObject.put("user_id", userId)
            jsonObject.put("accountBalances", accountBalances)
            jsonObject.put("objCurrentBetting", jsonCurrentBetting)
           // Log.d("JSON", jsonObject.toString())

            socketService.startEmitCreateBetting(jsonObject)
        } catch (e: URISyntaxException) {
            e.printStackTrace()
        }
    }

    fun stopListeningToSocketServer() {
        //if(prefHelper.getToken().isEmpty()) return
        socketService.unregisterListener(this)
        socketService.stopListening()
    }

    // Server callbacks

    // Server callbacks
    override fun onConnect() {
        connectivityStateLD.postValue(ConnectivityStates.STATE_CONNECTED)
    }

    override fun onReconnectionTimeout() {
        connectivityStateLD.postValue(ConnectivityStates.STATE_TIMEOUT)
    }
    override fun onConnectionError() {
        connectivityStateLD.postValue(ConnectivityStates.STATE_NOT_CONNECTED)
    }

    override fun onReconnect() {
        connectivityStateLD.postValue(ConnectivityStates.STATE_RECONNECTING)
    }

    override fun onDisconnect() {
        connectivityStateLD.postValue(ConnectivityStates.STATE_DISCONNECTED)
    }

    override fun onNewCreatedBettingMessage(createdBettingJsonObject: JSONObject) {
        newCreatedBetting.postValue(createdBettingJsonObject)
    }

    override fun onNewLottoMessage(chatMessage: SocketMessageDataModel) {

        newMessagesLotto.postValue(chatMessage)

    }

    private fun prevShare() = shareState.value!!

    private fun prevResult() = resultState.value!!

    private fun prevReport() = reportState.value!!




}