package com.gh.gamecenter.gamedetail.rating

import android.app.Application
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.gamecenter.common.base.fragment.WaitingDialogFragment
import com.gh.gamecenter.common.exposure.meta.MetaUtil
import com.gh.gamecenter.common.json.json
import com.gh.common.util.*
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.common.callback.ConfirmListener
import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.common.baselist.LoadStatus
import com.gh.gamecenter.common.baselist.LoadType
import com.gh.gamecenter.common.entity.ErrorEntity
import com.gh.gamecenter.common.utils.toObject
import com.gh.gamecenter.common.utils.toRequestBody
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.utils.ApkActiveUtils
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import retrofit2.HttpException

class RatingReplyViewModel(
    application: Application,
    private val gameId: String?,
    var game: GameEntity?,
    val commentId: String?,
    var comment: RatingComment?,
    var showKeyboardIfReplyIsEmpty: Boolean,
    var topCommentId: String
) : ListViewModel<RatingReplyEntity, RatingReplyItem>(application) {

    private val mApi = RetrofitManager.getInstance().api
    private val mSensitiveApi = RetrofitManager.getInstance().api
    private val mRealLoadStatusLiveData = MediatorLiveData<LoadStatus>()

    val headDataLiveData = MediatorLiveData<Boolean>()
    val processDialog = MediatorLiveData<WaitingDialogFragment.WaitingDialogData>()
    var lastPageData = hashMapOf<String, String>()

    private var mSortValue = SORT_POSITIVE
    private var isHandleTopComment = false

    init {
        mRealLoadStatusLiveData.addSource(mLoadStatusLiveData) {
            when (it) {
                LoadStatus.INIT_OVER, LoadStatus.INIT_EMPTY -> mRealLoadStatusLiveData.postValue(LoadStatus.LIST_OVER)
                LoadStatus.INIT_FAILED -> mRealLoadStatusLiveData.postValue(LoadStatus.LIST_FAILED)
                LoadStatus.INIT_LOADING -> mRealLoadStatusLiveData.postValue(LoadStatus.LIST_LOADING)
                LoadStatus.INIT_LOADED -> mRealLoadStatusLiveData.postValue(LoadStatus.LIST_LOADED)
                else -> mRealLoadStatusLiveData.postValue(it)
            }
        }

        initData()
    }

    fun initData() {
        if (!gameId.isNullOrEmpty()) {
            getGameDigest()
        } else if (game != null && comment != null) {
            mListLiveData.postValue(null) // init Head
            load(LoadType.REFRESH)
        } else {
            getGameDigest()
        }
    }

    override fun getLoadStatusLiveData(): LiveData<LoadStatus> {
        return mRealLoadStatusLiveData
    }

    override fun provideDataObservable(page: Int): Observable<List<RatingReplyEntity>> {
        val map = hashMapOf<String, Any>()
        if (!isHandleTopComment && topCommentId.isNotEmpty()) {
            map["top_comment_id"] = topCommentId
        }
        return mApi.getCommentReply(game?.id, comment?.id, mSortValue, page, map)
    }

    override fun mergeResultLiveData() {
        mResultLiveData.addSource(mListLiveData) { list ->
            val itemList = ArrayList<RatingReplyItem>()
            val gameItem = RatingReplyItem()
            gameItem.game = game
            itemList.add(gameItem)

            val commentItem = RatingReplyItem()
            commentItem.comment = comment
            itemList.add(commentItem)

            if (comment != null) {
                val replyCountItem = RatingReplyItem()
                if (list != null && list.size > comment!!.reply) {
                    replyCountItem.replyCount = list.size
                    comment?.reply = list.size
                    itemList.add(replyCountItem)
                } else if (comment!!.reply > 0) {
                    replyCountItem.replyCount = comment?.reply
                    itemList.add(replyCountItem)
                }
            }

            list?.forEachIndexed { index, entity ->
                val replyItem = RatingReplyItem()
                replyItem.reply = entity
                handleTopComment(index, entity)
                itemList.add(replyItem)
            }
            mResultLiveData.postValue(itemList)
        }
    }

    private fun handleTopComment(index: Int, entity: RatingReplyEntity) {
        if (!isHandleTopComment && game != null && comment != null && topCommentId.isNotBlank() && index == 0) {
            isHandleTopComment = true
            entity.isHighlight = true
        }
    }

    // 获取游戏摘要
    private fun getGameDigest() {
        mSensitiveApi.getGameDigest(gameId)
            .map(ApkActiveUtils.filterMapper)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : Response<GameEntity>() {
                override fun onResponse(response: GameEntity?) {
                    game = response
                    if (comment == null) {
                        getCommentDigest()
                    } else {
                        load(LoadType.REFRESH)
                        headDataLiveData.postValue(true)
                    }
                }

                override fun onFailure(e: HttpException?) {
                    if (e?.code() == 404) {
                        mRealLoadStatusLiveData.postValue(LoadStatus.INIT_EXCEPTION)
                        Utils.toast(getApplication(), com.gh.gamecenter.common.R.string.comment_failed_unable)
                    } else {
                        mRealLoadStatusLiveData.postValue(LoadStatus.INIT_FAILED)
                    }
                }
            })
    }

    private fun getCommentDigest() {
        mApi.getGameComment(gameId, commentId)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : Response<RatingComment>() {
                override fun onResponse(response: RatingComment?) {
                    response?.replyData = null
                    comment = response
                    load(LoadType.REFRESH)
                    headDataLiveData.postValue(true)
                }

                override fun onFailure(e: HttpException?) {
                    if (e?.code() == 404) {
                        mRealLoadStatusLiveData.postValue(LoadStatus.INIT_EXCEPTION)
                        Utils.toast(getApplication(), com.gh.gamecenter.common.R.string.comment_failed_unable)
                    } else {
                        mRealLoadStatusLiveData.postValue(LoadStatus.INIT_FAILED)
                    }
                    headDataLiveData.postValue(false)
                }
            })
    }

    fun replyComment(
        replyId: String?,
        content: String,
        successCallback: () -> Unit,
        realNameConfirmListener: ConfirmListener
    ) {
        processDialog.postValue(WaitingDialogFragment.WaitingDialogData("提交中...", true))

        val json = json {
            "content" to content
            "device" to json {
                "os" to "Android"
                "rom" to MetaUtil.getMeta().rom
                "model" to MetaUtil.getMeta().model
                "manufacturer" to MetaUtil.getMeta().manufacturer
                "android_sdk" to MetaUtil.getMeta().android_sdk
                "android_version" to MetaUtil.getMeta().android_version
                "gh_version" to BuildConfig.VERSION_NAME
            }
        }
        val body = json.toRequestBody()
        val observable =
            if (replyId.isNullOrEmpty()) {
                mApi.postCommentReply(game?.id, comment?.id, body)
            } else {
                mApi.postReplyToReply(game?.id, comment?.id, replyId, body)
            }
        observable
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : Response<ResponseBody>() {
                override fun onResponse(response: ResponseBody?) {
                    super.onResponse(response)
                    processDialog.postValue(
                        WaitingDialogFragment.WaitingDialogData(
                            "提交中...",
                            false
                        )
                    )
                    Utils.toast(getApplication(), "发表成功")
                    successCallback.invoke()
                    comment!!.reply = comment!!.reply + 1
                    load(LoadType.REFRESH)
                }

                override fun onFailure(e: HttpException?) {
                    super.onFailure(e)
                    processDialog.postValue(
                        WaitingDialogFragment.WaitingDialogData(
                            "提交中...",
                            false
                        )
                    )
                    ErrorHelper.handleError(
                        getApplication(),
                        e?.response()?.errorBody()?.string(),
                        false,
                        "游戏评论及回复",
                        "社区实名",
                        realNameConfirmListener = realNameConfirmListener
                    )
                }
            })
    }

    fun voteReply(replyId: String, isVote: Boolean = true, callback: () -> Unit) {
        val observable = if (isVote) {
            mApi.postReplyVote(game?.id, comment?.id, replyId)
        } else {
            mApi.postReplyUnvote(game?.id, comment?.id, replyId)
        }
        observable
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : Response<ResponseBody>() {
                override fun onResponse(response: ResponseBody?) {
                    Utils.toast(getApplication(), if (isVote) "点赞成功" else "取消点赞")

                    val list = mListLiveData.value
                    if (list != null) {
                        for (entity in list) {
                            if (entity.id == replyId) {
                                entity.me.isVoted = isVote
                                entity.vote = if (isVote) entity.vote + 1 else entity.vote - 1
                            }
                        }
                    }
                    callback.invoke()
                }

                override fun onFailure(e: HttpException?) {
                    val string = e?.response()?.errorBody()?.string()
                    val errorEntity = string?.toObject<ErrorEntity>()
                    if (errorEntity?.code == 403008) {
                        onResponse(null)
                        return
                    }
                    ErrorHelper.handleError(getApplication(), e?.response()?.errorBody()?.string())
                }
            })
    }

    fun voteComment(callback: () -> Unit) {
        mApi.voteGameComment(game?.id, comment?.id)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : Response<ResponseBody>() {
                override fun onResponse(response: ResponseBody?) {
                    Utils.toast(getApplication(), "点赞成功")
                    callback.invoke()
                }

                override fun onFailure(e: HttpException?) {
                    val string = e?.response()?.errorBody()?.string()
                    val errorEntity = string?.toObject<ErrorEntity>()
                    if (errorEntity?.code == 403008) {
                        onResponse(null)
                        return
                    }
                    ErrorHelper.handleError(getApplication(), e?.response()?.errorBody()?.string())
                }
            })
    }

    fun unvoteComment(callback: () -> Unit) {
        mApi.unvoteGameComment(game?.id, comment?.id)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : Response<ResponseBody>() {
                override fun onResponse(response: ResponseBody?) {
                    Utils.toast(getApplication(), "取消点赞")
                    callback.invoke()
                }

                override fun onFailure(e: HttpException?) {
                    val string = e?.response()?.errorBody()?.string()
                    ErrorHelper.handleError(getApplication(), string)
                }
            })
    }

    fun sortList(sortValue: String) {
        this.mSortValue = sortValue
        load(LoadType.REFRESH)
    }

    class Factory(
        private val gameId: String?,
        private val game: GameEntity?,
        private val commentId: String?,
        private val comment: RatingComment?,
        private val showKeyboardIfReplyIsEmpty: Boolean,
        private val topCommentId: String
    ) : ViewModelProvider.NewInstanceFactory() {

        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            comment?.replyData = null // 不需要显示回复引用区域
            return RatingReplyViewModel(
                HaloApp.getInstance().application,
                gameId,
                game,
                commentId,
                comment,
                showKeyboardIfReplyIsEmpty,
                topCommentId
            ) as T
        }
    }

    companion object {
        const val SORT_POSITIVE = "time:1"
        const val SORT_NEGATION = "time:-1"
    }
}