package com.gh.gamecenter.mygame

import android.annotation.SuppressLint
import android.app.Application
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.therouter.TheRouter
import com.gh.common.repository.ReservationRepository
import com.gh.common.util.ReservationHelper.getReserveRequestBody
import com.gh.gamecenter.core.runOnUiThread
import com.gh.download.DownloadManager
import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.common.baselist.LoadType
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.common.utils.toRequestBody
import com.gh.gamecenter.core.provider.IPushProvider
import com.gh.gamecenter.livedata.Event
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.halo.assistant.fragment.reserve.ReserveReminderRepository
import com.lightgame.utils.Utils
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody

class MyReservationViewModel(application: Application) : ListViewModel<GameEntity, GameEntity>(application) {

    var positionAndPackageMap = HashMap<String, Int>() // key: packageName + position, value: position

    private val repository = ReserveReminderRepository.newInstance()
    private val compositeDisposable = CompositeDisposable()

    override fun provideDataObservable(page: Int): Observable<List<GameEntity>>? {
        return null
    }

    override fun provideDataSingle(page: Int): Single<MutableList<GameEntity>> {
        return RetrofitManager.getInstance().newApi
            .getGameReservations(page, Utils.getTime(getApplication()))
    }

    override fun mergeResultLiveData() {
        mResultLiveData.addSource(mListLiveData) {
            positionAndPackageMap.clear()
            it.forEachIndexed { index, gameEntity ->
                gameEntity.hideSizeInsideDes = true
                addGamePositionAndPackage(gameEntity, index)
            }
            mResultLiveData.postValue(it)
        }
    }

    private fun addGamePositionAndPackage(game: GameEntity, position: Int) {
        var packages = ""
        for (apkEntity in game.getApk()) {
            packages += apkEntity.packageName
        }
        packages += game.simulator?.apk?.packageName
        positionAndPackageMap[packages + position] = position
        game.setEntryMap(DownloadManager.getInstance().getEntryMap(game.name))
    }

    fun cancelReservation(game: GameEntity) {
        deleteOrCancelReservation(game, false)
    }

    @SuppressLint("CheckResult")
    private fun deleteOrCancelReservation(game: GameEntity, deleteReservation: Boolean) {
        val single = if (deleteReservation) {
            RetrofitManager.getInstance().newApi
                .deleteGameReservation(game.id, getReserveRequestBody(game, HaloApp.getInstance().application))
                .subscribeOn(Schedulers.io())
        } else {
            RetrofitManager.getInstance().newApi
                .cancelGameReservation(game.id, getReserveRequestBody(game, HaloApp.getInstance().application))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
        }

        single.subscribe(object : BiResponse<ResponseBody>() {
            override fun onSuccess(data: ResponseBody) {
                ReservationRepository.refreshReservations()

                if (deleteReservation) {
//                    MtaHelper.onEvent("预约游戏", "取消预约", game.name)
                } else {
//                    MtaHelper.onEvent("预约游戏", "删除预约", game.name)
                }

                val list = mListLiveData.value
                // 当数据量为1的时候不删了，直接刷新
                if (list?.size == 1) {
                    runOnUiThread { load(LoadType.REFRESH) }
                } else {
                    list?.remove(list.find { it.id == game.id })
                    mListLiveData.postValue(list)
                }
            }

            override fun onFailure(exception: Exception) {
                Utils.toast(getApplication(), exception.message)
                exception.printStackTrace()
            }
        })
    }

    private val _enableAutoDownloadSuccessfully = MutableLiveData<Event<Boolean>>()
    val enableAutoDownloadSuccessfully: LiveData<Event<Boolean>> = _enableAutoDownloadSuccessfully
    fun enableAutoDownload(enable: Boolean, games: Set<GameEntity>) {
        if (enable) {
            games.forEach {
                SensorsBridge.trackOpenAppointmentAutomaticDownload(it.id, it.name ?: "", it.categoryChinese)
            }
        } else {
            games.forEach {
                SensorsBridge.trackCancelAppointmentAutomaticDownload(it.id, it.name ?: "", it.categoryChinese)
            }
        }
        val params = createParamsInBatch(games).apply {
            put("wifi_auto_download", enable)
        }
        repository.enableAutoDownloadInBatches(params.toRequestBody())
            .map {
                val oldList = mResultLiveData.value ?: emptyList()
                val newList = oldList.map { item ->
                    if (games.any { it.id == item.id }) {
                        item.copy(_wifiAutoDownload = enable)
                    } else {
                        item
                    }

                }
                newList
            }
            .compose(singleToMain())
            .subscribe(object : BiResponse<List<GameEntity>>() {
                override fun onSuccess(data: List<GameEntity>) {
                    mResultLiveData.value = data
                    _enableAutoDownloadSuccessfully.value = Event(enable)
                }

            }).let(compositeDisposable::add)
    }

    fun cancelReserveInBatch(games: Set<GameEntity>) {
        val params = createParamsInBatch(games).apply {
            put("appointment", false)
        }
        repository.cancelReserveInBatch(params.toRequestBody())
            .subscribeOn(Schedulers.io())
            .subscribe(object : BiResponse<ResponseBody>() {
                override fun onSuccess(data: ResponseBody) {
                    ReservationRepository.refreshReservations()
                    val oldList = mResultLiveData.value ?: emptyList()
                    val newList = oldList.toMutableList()

                    newList.removeAll {
                        games.any { game -> game.id == it.id }
                    }
                    if (newList.isEmpty()) {
                        // 刷新页面
                        runOnUiThread { load(LoadType.REFRESH) }
                    } else {
                        mResultLiveData.postValue(newList)
                    }

                }

            }).let(compositeDisposable::add)
    }

    private fun createParamsInBatch(games: Set<GameEntity>): HashMap<String, Any> {
        val jPushId =
            (TheRouter.get(IPushProvider::class.java)
                ?.getRegistrationId(HaloApp.getInstance().application)) ?: ""
        val idAndMirrorType = games.map {
            var mirrorPosition = it.getMirrorPosition()
            if (mirrorPosition == -1) {
                mirrorPosition = 0
            }
            hashMapOf("_id" to it.id, "mirror_type" to mirrorPosition)
        }
        return hashMapOf("jpush_id" to jPushId, "games" to idAndMirrorType)
    }

    private val _changePageStateAction = MutableLiveData<Event<MyReservationFragment.ReservePageState>>()
    val changePageStateAction: LiveData<Event<MyReservationFragment.ReservePageState>> = _changePageStateAction
    fun changeReserveStatus(state: MyReservationFragment.ReservePageState) {
        _changePageStateAction.value = Event(state)
    }

    override fun onCleared() {
        super.onCleared()
        compositeDisposable.clear()
    }

}