package com.gh.gamecenter.collection

import android.annotation.SuppressLint
import android.app.Application
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.gamecenter.core.AppExecutor
import com.gh.common.history.HistoryDatabase
import com.gh.common.history.HistoryHelper
import com.gh.common.util.ErrorHelper
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.common.utils.observableToMain
import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.common.baselist.LoadType
import com.gh.gamecenter.collection.GamesCollectionFragment.Companion.TYPE_COLLECT
import com.gh.gamecenter.collection.GamesCollectionFragment.Companion.TYPE_HISTORY
import com.gh.gamecenter.entity.GamesCollectionEntity
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.Single
import okhttp3.ResponseBody
import retrofit2.HttpException

class GamesCollectionViewModel(
    application: Application,
    var userId: String,
    var type: String,
    val mIsInsertGameCollection: Boolean = false
) :
    ListViewModel<GamesCollectionEntity, GamesCollectionEntity>(application) {

    private val mApi = RetrofitManager.getInstance().api
    val deleteLiveData = MutableLiveData<GamesCollectionEntity>()
    val publishLiveData = MutableLiveData<GamesCollectionEntity>()

    override fun provideDataObservable(page: Int) = null

    override fun provideDataSingle(page: Int): Single<MutableList<GamesCollectionEntity>> {
        return when (type) {
            TYPE_COLLECT -> mApi.getFavoriteGameCollectionList(userId, page)

            TYPE_HISTORY -> {
                if (page > 5) {
                    Single.create { it.onSuccess(arrayListOf()) }
                } else {
                    HistoryDatabase.instance.gamesCollectionDao().getGamesCollectionWithOffset(20, (page - 1) * 20)
                }
            }

            else -> {
                val map = if (mIsInsertGameCollection) {
                    mapOf("filter" to "display:", "page" to page)
                } else mapOf(
                    "page" to page,
                    "page_size" to 15
                )
                mApi.getUserGameCollectionList(userId, map)
            }
        }
    }

    override fun mergeResultLiveData() {
        mResultLiveData.addSource(mListLiveData) {
            mResultLiveData.postValue(it)
        }
    }

    fun deleteGameCollection(entity: GamesCollectionEntity) {
        mApi.deleteGameCollection(entity.id)
            .compose(observableToMain())
            .subscribe(object : Response<ResponseBody>() {
                override fun onResponse(response: ResponseBody?) {
                    super.onResponse(response)
                    deleteLiveData.postValue(entity)
                }

                override fun onFailure(e: HttpException?) {
                    super.onFailure(e)
                    ToastUtils.showToast("删除失败")
                }
            })
    }

    fun publishGameCollection(entity: GamesCollectionEntity) {
        mApi.publishGameCollection(entity.id)
            .compose(observableToMain())
            .subscribe(object : Response<ResponseBody>() {
                override fun onResponse(response: ResponseBody?) {
                    super.onResponse(response)
                    publishLiveData.postValue(entity)
                }

                override fun onFailure(e: HttpException?) {
                    super.onFailure(e)
                    ToastUtils.showToast("投稿失败")
                }
            })
    }

    @SuppressLint("CheckResult")
    fun postVoteGameCollection(gameCollectionId: String, isVote: Boolean, successCallback: (() -> Unit)) {
        val single = if (isVote) {
            mApi.voteGameCollection(gameCollectionId)
        } else {
            mApi.unVoteGameCollection(gameCollectionId)
        }
        single.compose(singleToMain())
            .subscribe(object : BiResponse<ResponseBody>() {
                override fun onSuccess(data: ResponseBody) {
                    ToastUtils.toast(if (isVote) "点赞成功" else "取消点赞")
                    successCallback.invoke()
                }

                override fun onFailure(exception: Exception) {
                    super.onFailure(exception)

                    if (exception is HttpException) {
                        ErrorHelper.handleError(
                            getApplication(),
                            exception.response()?.errorBody()?.string()
                        )
                    }
                }
            })
    }

    fun removeHistory(gamesCollectionEntity: GamesCollectionEntity) {
        mResultLiveData.value?.let {
            HistoryHelper.deleteGamesCollectionEntity(gamesCollectionEntity.id)

            it.remove(gamesCollectionEntity)
            if (it.size == 0) {
                AppExecutor.uiExecutor.executeWithDelay(Runnable { load(LoadType.REFRESH) }, 100)
            } else {
                mResultLiveData.postValue(it)
            }
        }
    }

    fun removeHistories(ids: List<String>) {
        mResultLiveData.value?.let { datas ->
            ids.forEach { id ->
                HistoryHelper.deleteGamesCollectionEntity(id)
                val entity = datas.find { it.id == id }
                datas.remove(entity)
            }
            if (datas.size == 0) {
                AppExecutor.uiExecutor.executeWithDelay({ load(LoadType.REFRESH) }, 100)
            } else {
                mResultLiveData.postValue(datas)
            }
        }
    }

    class Factory(
        private val mUserId: String,
        private val mType: String,
        private val mIsInsertGameCollection: Boolean
    ) :
        ViewModelProvider.NewInstanceFactory() {
        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            return GamesCollectionViewModel(
                HaloApp.getInstance().application,
                mUserId,
                mType,
                mIsInsertGameCollection
            ) as T
        }
    }

}