package com.gh.gamecenter.gamecollection.detail

import android.annotation.SuppressLint
import android.app.Application
import android.net.Uri
import android.os.Build
import android.text.TextUtils
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.syncpage.SyncDataEntity
import com.gh.gamecenter.common.syncpage.SyncFieldConstants
import com.gh.gamecenter.common.syncpage.SyncPageRepository
import com.gh.common.util.*
import com.gh.gamecenter.R
import com.gh.gamecenter.common.baselist.LoadStatus
import com.gh.gamecenter.common.utils.observableToMain
import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.common.utils.toNewSimpleCount
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.entity.CommentEntity
import com.gh.gamecenter.entity.GamesCollectionDetailEntity
import com.gh.gamecenter.eventbus.EBUserFollow
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.qa.article.detail.CommentItemData
import com.gh.gamecenter.qa.comment.base.BaseCommentViewModel
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.retrofit.EmptyResponse
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import org.greenrobot.eventbus.EventBus
import org.json.JSONObject
import retrofit2.HttpException
import tv.danmaku.ijk.media.exo2.ExoSourceManager

open class GameCollectionDetailViewModel(
    application: Application,
    var gameCollectionId: String,
    topCommentId: String = ""
) :
    BaseCommentViewModel(application, "", "", "", "", topCommentId) {

    var firstItemInitOverLiveData = MutableLiveData<Boolean>()
    var followLiveData = MutableLiveData<Boolean>()
    val favoriteLiveData = MutableLiveData<Boolean>()
    val likeLiveData = MutableLiveData<Boolean>()
    val shareLiveData = MutableLiveData<Boolean>()
    var gameCollectionDetail: GamesCollectionDetailEntity? = null
    var gameCollectionTitle = ""
    var ownerUserId = ""
    var filterPos = 0
    var displayTopVideo: Boolean = false
    var videoIsMuted = SPUtils.getBoolean(Constants.SP_VIDEO_PLAY_MUTE, true)
    var isPostFirstOver = false

    @SuppressLint("CheckResult")
    fun getGameCollectionDetail() {
        mApi.getGameCollectionDetail(gameCollectionId)
            .compose(singleToMain())
            .subscribe(object : BiResponse<GamesCollectionDetailEntity>() {
                override fun onSuccess(data: GamesCollectionDetailEntity) {
                    // 4.4以下设备不显示顶部视频
                    displayTopVideo = data.video != null
                            && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
                    gameCollectionDetail = data
                    gameCollectionTitle = data.title
                    commentCount = data.count?.comment ?: 0
                    ownerUserId = data.user?.id ?: ""
                    filterPos = if (data.games.isNullOrEmpty()) 2 else data.games!!.size + 1
                    loadResultLiveData.postValue(LoadResult.SUCCESS)
                    mergeData(mListLiveData.value)
                }

                override fun onFailure(exception: Exception) {
                    super.onFailure(exception)
                    if (exception is HttpException && exception.code().toString().startsWith("404")) {
                        loadResultLiveData.postValue(LoadResult.DELETED)
                    } else {
                        loadResultLiveData.postValue(LoadResult.NETWORK_ERROR)
                    }
                }
            })
    }

    override fun provideDataObservable(page: Int) = null

    override fun provideDataSingle(page: Int): Single<MutableList<CommentEntity>> {
        val map = hashMapOf<String, Any>()
        map["sort"] = if (currentSortType == SortType.LATEST) "latest" else "earliest"
        if (!isHandleTopComment && topCommentId.isNotBlank()) {
            map["top_comment_id"] = topCommentId
        }
        return mApi.getGameCollectionComments(gameCollectionId, page, map)
    }

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

    fun mergeData(list: List<CommentEntity>?) {
        gameCollectionDetail?.run {
            val itemDataList = arrayListOf<CommentItemData>().apply {
                if (games.isNullOrEmpty()) {
                    add(CommentItemData(gameEmpty = true))
                } else {
                    val gameLastIndex = games!!.size - 1
                    if (mResultLiveData.value?.get(0)?.game != null
                        && mResultLiveData.value?.get(gameLastIndex)?.game != null
                    ) {
                        for (i in 0..gameLastIndex) {
                            add(mResultLiveData.value!![i])
                        }
                    } else {
                        games?.forEach {
                            it.isAdData = adIconActive
                            add(CommentItemData(game = it))
                        }
                    }
                }

                add(CommentItemData(divider = true))
                add(CommentItemData(filter = true))

                if (list.isNullOrEmpty() && mLoadStatusLiveData.value == LoadStatus.INIT_EMPTY) {
                    add(CommentItemData(errorEmpty = true))
                } else if (list.isNullOrEmpty() && mLoadStatusLiveData.value == LoadStatus.INIT_FAILED) {
                    add(CommentItemData(errorConnection = true))
                } else {
                    list?.forEachIndexed { index, entity ->
                        handleTopComment(index, entity)
                        add(CommentItemData(commentNormal = entity))
                    }
                    add(CommentItemData(footer = true))
                }
            }

            mResultLiveData.postValue(itemDataList)
        }
    }

    override fun getHandleTopCommentCondition(index: Int) =
        !isHandleTopComment && gameCollectionDetail != null && topCommentId.isNotBlank() && index == 0

    fun followingCommand(userId: String, isFollow: Boolean) {
        val observable = if (isFollow) {
            RetrofitManager.getInstance().api.postFollowing(userId)
        } else {
            RetrofitManager.getInstance().api.deleteFollowing(userId)
        }
        observable
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : Response<ResponseBody>() {
                override fun onResponse(response: ResponseBody?) {
                    super.onResponse(response)
                    if (isFollow) {
                        Utils.toast(getApplication(), R.string.concern_success)
                    } else {
                        Utils.toast(getApplication(), R.string.concern_cancel)
                    }
                    gameCollectionDetail?.me?.isFollower =
                        gameCollectionDetail?.me?.isFollower != true
                    followLiveData.postValue(isFollow)
                    EventBus.getDefault().post(EBUserFollow(userId, isFollow))
                }

                override fun onFailure(e: HttpException?) {
                    super.onFailure(e)
                    Utils.toast(getApplication(), R.string.loading_failed_hint)
                }
            })
    }

    @SuppressLint("CheckResult")
    fun postFavoriteGameCollection() {
        if (gameCollectionDetail == null) return
        val single = if (gameCollectionDetail?.me?.isFavorite == true) {
            mApi.deleteFavoriteGameCollection(UserManager.getInstance().userId, gameCollectionId)
        } else {
            mApi.favoriteGameCollection(UserManager.getInstance().userId, gameCollectionId)
        }
        single.compose(singleToMain())
            .subscribe(object : BiResponse<ResponseBody>() {
                override fun onSuccess(data: ResponseBody) {
                    if (gameCollectionDetail?.me?.isFavorite == true) {
                        gameCollectionDetail!!.count!!.favorite--
                        ToastUtils.showToast("取消收藏")
                    } else {
                        gameCollectionDetail!!.count!!.favorite++
                        ToastUtils.showToast("收藏成功")
                    }
                    gameCollectionDetail?.me?.isFavorite =
                        gameCollectionDetail?.me?.isFavorite != true
                    favoriteLiveData.postValue(true)
                }

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

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

    @SuppressLint("CheckResult")
    fun postVoteGameCollection() {
        if (gameCollectionDetail == null) return
        val single = if (gameCollectionDetail?.me?.isVoted == true) {
            mApi.unVoteGameCollection(gameCollectionId)
        } else {
            mApi.voteGameCollection(gameCollectionId)
        }
        single.compose(singleToMain())
            .subscribe(object : BiResponse<ResponseBody>() {
                override fun onSuccess(data: ResponseBody) {
                    if (gameCollectionDetail?.me?.isVoted == true) {
                        gameCollectionDetail!!.count!!.vote--
                        ToastUtils.showToast("取消点赞")
                    } else {
                        gameCollectionDetail!!.count!!.vote++
                        ToastUtils.showToast("点赞成功")
                    }
                    gameCollectionDetail?.me?.isVoted =
                        gameCollectionDetail?.me?.isVoted != true
                    likeLiveData.postValue(true)
                    syncGameCollectionVoteData()
                }

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

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

    private fun syncGameCollectionVoteData() {
        gameCollectionId.apply {
            SyncPageRepository.postSyncData(
                SyncDataEntity(
                    this,
                    SyncFieldConstants.ARTICLE_VOTE_COUNT,
                    gameCollectionDetail?.count?.vote,
                    checkFieldEntity = true
                )
            )
            SyncPageRepository.postSyncData(
                SyncDataEntity(
                    this,
                    SyncFieldConstants.GAME_COLLECTION_VOTE,
                    gameCollectionDetail?.me?.isVoted,
                    checkFieldEntity = true
                )
            )
        }
    }

    @SuppressLint("CheckResult")
    fun postShareGameCollection() {
        postGameCollectionTask("forward_share_game_list")

        if (gameCollectionDetail == null) return
        mApi.shareGameCollection(gameCollectionId)
            .compose(singleToMain())
            .subscribe(object : BiResponse<ResponseBody>() {
                override fun onSuccess(data: ResponseBody) {
                    gameCollectionDetail!!.count!!.share++
                    shareLiveData.postValue(true)
                }

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

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


    @SuppressLint("CheckResult")
    fun postVoteGameCollectionComment(comment: CommentEntity, successCallback: (() -> Unit)) {
        mApi.voteGameCollectionComment(gameCollectionId, comment.id)
            .compose(singleToMain())
            .subscribe(object : BiResponse<ResponseBody>() {
                override fun onSuccess(data: ResponseBody) {
                    if (comment.me?.isCommentVoted == true) {
                        comment.vote--
                        ToastUtils.showToast("取消点赞")
                    } else {
                        comment.vote++
                        ToastUtils.showToast("点赞成功")
                    }
                    comment.me?.isCommentVoted = !(comment.me?.isCommentVoted ?: false)
                    successCallback.invoke()
                    syncGameCollectionCommentVoteData(comment)
                }

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

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

    private fun syncGameCollectionCommentVoteData(comment: CommentEntity) {
        comment.id?.let {
            SyncPageRepository.postSyncData(
                SyncDataEntity(
                    it,
                    SyncFieldConstants.ARTICLE_COMMENT_VOTE_COUNT,
                    comment.vote
                )
            )
            SyncPageRepository.postSyncData(
                SyncDataEntity(
                    it,
                    SyncFieldConstants.ARTICLE_COMMENT_VOTE,
                    comment.me?.isCommentVoted,
                    checkFieldEntity = true
                )
            )
        }
    }

    @SuppressLint("CheckResult")
    override fun deleteComment(entity: CommentEntity, callback: () -> Unit) {
        mApi.deleteGameCollectionComment(gameCollectionId, entity.id)
            .compose(observableToMain())
            .subscribe(object : Response<ResponseBody>() {
                override fun onResponse(response: ResponseBody?) {
                    hideCommentSuccess()
                    callback.invoke()
                }

                override fun onFailure(e: HttpException?) {
                    super.onFailure(e)
                    e?.let { httpException ->
                        if (httpException.code() == 403) {
                            val string = e.response().errorBody()?.string() ?: ""
                            val errorJson = JSONObject(string)
                            val errorCode = errorJson.getInt("code")
                            if (errorCode == 403059) {
                                Utils.toast(getApplication(), "权限错误，请刷新后重试")
                                return
                            } else {
                                Utils.toast(getApplication(), e.message())
                            }
                        }
                    }
                }
            })
    }

    @SuppressLint("CheckResult")
    fun postGameCollectionTask(event: String, gameCollectionId: String = "0") {
        RetrofitManager.getInstance()
            .newApi
            .postGameCollectionTask(event, gameCollectionId)
            .compose(singleToMain())
            .subscribe(EmptyResponse())
    }

    fun getStarText(): String {
        val favoriteCount = gameCollectionDetail?.count?.favorite ?: 0
        return when {
            favoriteCount == 0 -> "收藏"
            favoriteCount > 10000 -> "10000+"
            else -> favoriteCount.toString()
        }
    }

    fun getShareText(): String {
        val shareCount = gameCollectionDetail?.count?.share ?: 0
        return when {
            shareCount == 0 -> "分享"
            shareCount > 10000 -> "10000+"
            else -> shareCount.toString()
        }
    }

    fun getLikeText() =
        when (val voteCount = gameCollectionDetail?.count?.vote ?: 0) {
            0 -> "赞同"
            else -> voteCount.toNewSimpleCount()
        }

    fun getCommentText() =
        when (val commentCount = gameCollectionDetail?.count?.comment ?: 0) {
            0 -> "评论"
            else -> commentCount.toNewSimpleCount()
        }

    fun isTopVideoPartlyCached(topVideoUrl: String): Boolean {
        val cache = ExoSourceManager.getCacheSingleInstance(HaloApp.getInstance().application, null)
        val key = Uri.parse(topVideoUrl).toString()
        return if (!TextUtils.isEmpty(key)) {
            val cachedSpans = cache.getCachedSpans(key)
            cachedSpans.size != 0
        } else {
            false
        }
    }

    fun postFirstItemInitOver() {
        if (!isPostFirstOver) {
            isPostFirstOver = true
            firstItemInitOverLiveData.postValue(true)
        }
    }

    class Factory(
        private val gameCollectionId: String,
        private val topCommentId: String
    ) :
        ViewModelProvider.NewInstanceFactory() {

        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            return GameCollectionDetailViewModel(
                HaloApp.getInstance().application,
                gameCollectionId,
                topCommentId
            ) as T
        }
    }
}