package com.gh.gamecenter.gamedetail.desc

import android.app.Application
import android.os.Build
import android.text.TextUtils
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.facebook.common.util.UriUtil
import com.gh.common.util.PackageUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.exposure.meta.MetaUtil
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.entity.SubjectEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.GameInfo
import com.gh.gamecenter.gamedetail.entity.CustomColumn
import com.gh.gamecenter.gamedetail.entity.DetailEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.google.gson.JsonArray
import com.google.gson.reflect.TypeToken
import com.halo.assistant.HaloApp
import com.walkud.rom.checker.RomIdentifier
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import org.json.JSONObject
import retrofit2.HttpException

class DescViewModel(
    application: Application,
    var game: GameEntity?
) : AndroidViewModel(application) {

    private var mDataList = arrayListOf<DetailEntity>()
    private var mRelatedGameList = arrayListOf<GameEntity>()

    private var mGameInfoPosition = 0
    private var mLibaoPosition = -1
    private var mServerPosition = -1
    private var mDetailLibaoPosition = -1
    private var mRelatedVersionPosition = -1
    private var mColumnRecommendPosition = -1
    private var mGameInfo: GameInfo? = null
    private val mIdMaps = hashMapOf<String, String>()
    private var mSubjectPage = 1
    var list = MutableLiveData<ArrayList<DetailEntity>>()
    var changeColumnGameLiveData = MutableLiveData<Boolean>()
    var gameId = game?.id

    /**
     * 构建大家都在玩的item
     */
    fun generateRecommendedGamesItem(mDataList: ArrayList<DetailEntity>) {
        this.mDataList = mDataList
        mIdMaps.clear()
        val detailEntity = mDataList.find { it.type == DetailEntity.Type.RECOMMENDED_GAMES.value } ?: return
        val relatedGames = detailEntity.relatedGames
        val installGames = detailEntity.installGames
        val downloadGames = detailEntity.downloadGames

        if (relatedGames.isNullOrEmpty()
            && installGames.isNullOrEmpty()
            && downloadGames.isNullOrEmpty()
        ) {
            assembleListWithRecommendedGames()
            return
        }

        val labelGames = arrayListOf<String>()
        for (relatedGame in relatedGames ?: listOf()) {
            relatedGame.game?.let {
                labelGames.addAll(it)
            }
        }

        if (labelGames.isNotEmpty()) {
            val gameIds = labelGames.take(4)
            gameIds.forEach {
                mIdMaps[it] = "标签推荐"
            }
        }
        val labelGameCount = mIdMaps.size

        if (installGames != null) {
            val gameIds = installGames.take(4)
            gameIds.forEach {
                mIdMaps[it] = "安装推荐"
            }
        }

        if (downloadGames != null) {
            val gameIds = downloadGames.take(4)
            gameIds.forEach {
                mIdMaps[it] = "下载推荐"
            }
        }

        if (mIdMaps.size < 6 && labelGames.size > labelGameCount) {
            for (i in labelGameCount until labelGames.size) {
                mIdMaps[labelGames[i]] = "标签推荐"
                if (mIdMaps.size >= 6) break
            }
        }

        if (mIdMaps.size < 6) {
            val entity = mDataList.find { it.type == DetailEntity.Type.RECOMMENDED_GAMES.value }
            mDataList.remove(entity)
            assembleListWithRecommendedGames()
            return
        }

        getGamesDigestByIds {
            mRelatedGameList.clear()
            mRelatedGameList.addAll(it)
            assembleListWithRecommendedGames()
        }
    }

    private fun getGamesDigestByIds(callback: (List<GameEntity>) -> Unit) {
        val ids = mIdMaps.map { it.key }.toList().joinToString("-")
        val filterQuery = UrlFilterUtils.getFilterQuery("game_ids", ids)
        RetrofitManager.getInstance().api.getGamesDigestByIds(filterQuery)
            .compose(observableToMain())
            .subscribe(object : Response<List<GameEntity>>() {
                override fun onResponse(response: List<GameEntity>?) {
                    super.onResponse(response)
                    response?.forEach { it.recommendType = mIdMaps[it.id] ?: "" }
                    response?.let(callback) ?: callback.invoke(listOf())
                }

                override fun onFailure(e: HttpException?) {
                    super.onFailure(e)
                    callback.invoke(listOf())
                }
            })
    }

    private fun assembleListWithRecommendedGames() {
        for ((index, data) in mDataList.withIndex()) {
            if (data.info != null) {
                mGameInfoPosition = index
                mGameInfo = data.info!!
            }

            if (data.server != null) {
                mServerPosition = index
            }

            if (data.libao != null) {
                mLibaoPosition = index
            }

            if (data.columnGames != null) {
                mColumnRecommendPosition = index
            }

            if (data.relatedGames != null) {
                mRelatedGameList.shuffle()
                val recommendedGames = SubjectEntity().apply {
                    this.data = mRelatedGameList
                }
                data.recommendedGames = recommendedGames
            }
        }
        list.postValue(mDataList)
    }

    fun changeSubjectGame(subjectId: String, gameCount: Int) {
        RetrofitManager.getInstance().api
            .getSubjectGame(subjectId, mSubjectPage)
            .compose(observableToMain())
            .subscribe(object : Response<retrofit2.Response<JsonArray>>() {
                override fun onResponse(response: retrofit2.Response<JsonArray>?) {
                    super.onResponse(response)
                    if (response == null) return
                    val total = response.headers().get("total")?.toInt() ?: 0
                    val isHasNextPage = (total - mSubjectPage * 20) > 0
                    val type = object : TypeToken<ArrayList<GameEntity>>() {}.type
                    val games = GsonUtils.gson.fromJson<ArrayList<GameEntity>>(response.body()?.toJson() ?: "", type)
                    val detailEntity =
                        mDataList.find { data -> data.type == DetailEntity.Type.COLUMN_RECOMMEND.value } ?: return
                    val randomArray = RandomUtils.getRandomArray(gameCount, games.size)
                    detailEntity.columnGames?.run {
                        clear()
                        for (i in randomArray) {
                            add(games[i])
                        }
                    }
                    changeColumnGameLiveData.postValue(true)
                    mSubjectPage = if (isHasNextPage) mSubjectPage + 1 else 1
                }

                override fun onFailure(e: HttpException?) {
                    super.onFailure(e)
                    changeColumnGameLiveData.postValue(false)
                }
            })
    }

    fun sendSuggestion() {
        val params = hashMapOf<String, String>()
        params["from"] = ""
        params["ghversion"] = PackageUtils.getGhVersionName()
        params["channel"] = HaloApp.getInstance().channel
        params["type"] = Build.MODEL
        params["sdk"] = android.os.Build.VERSION.SDK_INT.toString()
        params["version"] = Build.VERSION.RELEASE
        params["source"] = HaloApp.getInstance().application.getString(R.string.app_name)
        params["jnfj"] = MetaUtil.getBase64EncodedIMEI()
        params["manufacturer"] = Build.MANUFACTURER
        params["rom"] = RomIdentifier.getRom().name + " " + RomIdentifier.getRom().versionName

        params["suggestion_type"] = "游戏求更新"
        params["game_id"] = game?.id ?: ""
        params["message"] =
            "求更新：${game?.name}(${game?.getApk()?.get(0)?.packageName}, ${game?.getApk()?.get(0)?.version})"
        val requestBody = params.createRequestBody()
        RetrofitManager.getInstance().api.postSuggestion(requestBody)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : Response<ResponseBody?>() {
                override fun onResponse(response: ResponseBody?) {
                    super.onResponse(response)
                    ToastUtils.showToast("感谢您的反馈信息，我们将尽快处理~")
                }

                override fun onFailure(e: HttpException?) {
                    super.onFailure(e)
                    e?.response()?.errorBody()?.let {
                        val content = JSONObject(it.string())
                        if (content.getInt("code") == 403208) {
                            ToastUtils.showToast("您已经提交过反馈信息，我们将尽快处理~")
                        }
                    }
                }
            })
    }

    // TODO 装饰操作放到子线程去做
    // 装饰列表数据
    fun decorateList(detailEntityList: ArrayList<DetailEntity>): ArrayList<DetailEntity> {
        val specialPadding = DisplayUtils.dip2px(12F)
        val defaultPadding = DisplayUtils.dip2px(15F)

        var containsFirstTimeExpandCustomColumnTags = false
        var hasShownCustomColumnTagsExpandHint =
            SPUtils.getBoolean(Constants.SP_HAS_SHOWN_EXPANDED_GAME_DETAIL_TAGS_HINT)

        // A 确定每个 item 的上下内边距
        for ((index, rawItem) in detailEntityList.withIndex()) {
            rawItem.paddingTop = defaultPadding
            rawItem.paddingBottom = defaultPadding

            if (index == 0) {
                rawItem.paddingTop = specialPadding
            }
        }

        // B 将游戏介绍转为简单的自定义栏目
        for (rawItem in detailEntityList) {
            if (rawItem.type == DetailEntity.Type.DES.value) {
                rawItem.type = DetailEntity.Type.CUSTOM_COLUMN.value
                rawItem.customColumn = CustomColumn(
                    name = "游戏简介",
                    order = 1,
                    nameIcon = UriUtil.getUriForResourceId(R.drawable.ic_game_desc).toString(),
                    des = rawItem.des,
                    isHtmlDes = false,
                    showDesRowNum = 3
                )
                break
            }
        }

        // C 标记"公告"、"自定义栏目"、"详细信息" 的UI样式是否合并在一起，处理置顶文章的内容
        for ((index, rawItem) in detailEntityList.withIndex()) {
            if (rawItem.type == DetailEntity.Type.NOTICE.value
                || rawItem.type == DetailEntity.Type.CUSTOM_COLUMN.value
                || rawItem.type == DetailEntity.Type.GAME_INFO.value
            ) {
                if (index + 1 != detailEntityList.size) {
                    val nextRawItem = detailEntityList[index + 1]
                    if (nextRawItem.type == DetailEntity.Type.CUSTOM_COLUMN.value
                        || nextRawItem.type == DetailEntity.Type.NOTICE.value
                        || nextRawItem.type == DetailEntity.Type.GAME_INFO.value
                    ) {
                        // 默认情况下 UI 与前后相连
                        rawItem.shouldBoundWithNextItem = true
                        nextRawItem.shouldBoundWithPreviousItem = true

                        // 特殊情况下，如果自定义栏目类型为按钮，且后续的项不是按钮就独立显示，后续的项也为按钮时合并显示 (仅按钮类型的自定义栏目合并)
                        if (rawItem.type == DetailEntity.Type.CUSTOM_COLUMN.value
                            && rawItem.customColumn?.link?.style == "button"
                        ) {
                            val nextItemIsButtonStyleCustomColumn =
                                (nextRawItem.type == DetailEntity.Type.CUSTOM_COLUMN.value && nextRawItem.customColumn?.link?.style == "button")

                            rawItem.paddingBottom = 0
                            rawItem.shouldBoundWithNextItem = nextItemIsButtonStyleCustomColumn
                            nextRawItem.shouldBoundWithPreviousItem = nextItemIsButtonStyleCustomColumn

                            rawItem.paddingTop = specialPadding
                            nextRawItem.paddingTop = specialPadding
                        }

                        // 若当前项不是自定义栏目按钮类型的项，并且下个项是自定义栏目的项，不合并相关 UI
                        if (nextRawItem.type == DetailEntity.Type.CUSTOM_COLUMN.value
                            && nextRawItem.customColumn?.link?.style == "button"
                            && (rawItem.type != DetailEntity.Type.CUSTOM_COLUMN.value
                                    || rawItem.customColumn?.link?.style != "button")
                        ) {
                            nextRawItem.shouldBoundWithPreviousItem = false
                            nextRawItem.paddingBottom = 0
                        }
                    }
                }
            }

            // 处理置顶文章
            if (rawItem.type == "article") {
                if (rawItem.articleTop != null && rawItem.articleTop?.size != 0) {
                    for ((i, article) in rawItem.articleTop!!.withIndex()) {
                        article.priority = Int.MAX_VALUE
                        rawItem.article?.add(i, article)
                    }
                    rawItem.articleTop?.clear()
                }
            }
        }

        // D 处理自定义栏目相关的东西
        for (rawItem in detailEntityList) {
            if (rawItem.type == DetailEntity.Type.CUSTOM_COLUMN.value) {
                // 判断自定义栏目的标签是否需要进入就自动展开
                if (rawItem.customColumn?.showInfoTagDesType == "first_expand"
                    && !SPUtils.getBoolean(Constants.SP_HAS_EXPANDED_GAME_DETAIL_TAGS)
                ) {
                    containsFirstTimeExpandCustomColumnTags = true
                    rawItem.customColumn?.showInfoTagDesType = "expand"
                }

                // 正文内容为空，但是后台配置了标签展开的默认展开
                if (rawItem.customColumn?.showInfoTag == true
                    && TextUtils.isEmpty(rawItem.customColumn?.des)
                ) {
                    rawItem.customColumn?.showInfoTagDesType = "expand"
                }

                // 判断是否显示标签展开提示
                if (rawItem.customColumn?.showInfoTagDes == true
                    && rawItem.customColumn?.infoTag?.size != 0
                    && rawItem.customColumn?.showInfoTagDesType != "expand"
                    && !hasShownCustomColumnTagsExpandHint
                ) {
                    rawItem.customColumn?.showExpandTagsHint = true
                    // 内存置为 true 避免出现多个提示
                    hasShownCustomColumnTagsExpandHint = true
                }

                // 不存在缩起正文的自定义栏目默认全显示
                if (TextUtils.isEmpty(rawItem.customColumn?.desBrief) && rawItem.customColumn?.name != "游戏简介") {
                    rawItem.customColumn?.showDesType = "all"
                }

                // 将自定义栏目正文内容里低版本 android 系统不支持的 HTML Tag 转为手动处理
                if (!TextUtils.isEmpty(rawItem.customColumn?.desBrief)) {
                    rawItem.customColumn?.desFull = rawItem.customColumn?.desFull?.replaceUnsupportedHtmlTag()
                    rawItem.customColumn?.desBrief = rawItem.customColumn?.desBrief?.replaceUnsupportedHtmlTag()
                }

                rawItem.customColumn?.des = rawItem.customColumn?.desFull
                    ?: rawItem.customColumn?.des
            }
        }

        for ((index, entity) in detailEntityList.withIndex()) {
            if (entity.libao != null) {
                mDetailLibaoPosition = index
            }
            if (entity.relatedVersion != null) {
                mRelatedVersionPosition = index
            }
        }

        if (containsFirstTimeExpandCustomColumnTags) {
            SPUtils.setBoolean(Constants.SP_HAS_EXPANDED_GAME_DETAIL_TAGS, true)
        }

        loadCustomColumnImageInAdvance(detailEntityList)

        return detailEntityList
    }

    fun getServerIndexPosition() = mServerPosition

    fun getLibaoIndexPosition() = mLibaoPosition

    fun getGameInfoPosition() = mGameInfoPosition

    fun getDetailLibaoPosition() = mDetailLibaoPosition

    fun getRelatedVersionPosition() = mRelatedVersionPosition

    fun getColumnRecommendPosition() = mColumnRecommendPosition

    fun getGameInfo() = mGameInfo

    /**
     * 预加载自定义栏目的标签小图标
     */
    private fun loadCustomColumnImageInAdvance(detailEntityList: ArrayList<DetailEntity>) {
        for (item in detailEntityList) {
            if (item.type == DetailEntity.Type.CUSTOM_COLUMN.value) {
                item.customColumn?.infoTag?.let {
                    for (tag in it) {
                        tryWithDefaultCatch {
                            ImageUtils.picasso.load(tag.icon).fetch()
                        }
                    }
                }
            }
        }
    }

    class Factory(
        private val mApplication: Application,
        private val game: GameEntity?
    ) : ViewModelProvider.NewInstanceFactory() {
        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            return DescViewModel(mApplication, game) as T
        }
    }

}