package com.gh.gamecenter.servers

import android.annotation.SuppressLint
import android.app.Application
import androidx.collection.ArrayMap
import androidx.collection.arrayMapOf
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import com.gh.common.util.*
import com.gh.download.DownloadManager
import com.gh.gamecenter.common.baselist.LoadStatus
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.countOccurrences
import com.gh.gamecenter.core.utils.UrlFilterUtils
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.ServerCalendarEntity
import com.gh.gamecenter.entity.ServerPublishEntity
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers

class GameServersContentViewModel(application: Application) : AndroidViewModel(application) {

    val locationMap: ArrayMap<String, ArrayList<Int>> = arrayMapOf()
    val listLiveData: MutableLiveData<Triple<String?, ArrayList<GameEntity>, Int>> = MutableLiveData()
    val loadStatusLiveData: MutableLiveData<Pair<String?, LoadStatus>> = MutableLiveData()
    var day: String? = null
    var hour: String? = null
    var tags: String? = null

    //    var type: String? = null
//    var mRealIndex = 0
    var mEntrance = ""
    var prevId: String? = null
    var nextId: String? = null
    var isInit = true

    init {
        loadData()
    }


    @SuppressLint("CheckResult")
    fun loadData(isRefresh: Boolean = false, action: String? = null) {
        if (isRefresh) {
            isInit = true
            prevId = null
            nextId = null
        }

        loadStatusLiveData.postValue(Pair(action, LoadStatus.INIT))

        if ((action == "down" && prevId?.isEmpty() == true) || action == "up" && nextId?.isEmpty() == true) {
            loadStatusLiveData.postValue(Pair(action, LoadStatus.INIT_OVER))
            return
        }

        val filterQuery = UrlFilterUtils.getFilterQuery(
            "day", day, "hour", hour, "tag", tags,
            "action", action, "prev_server_id", prevId, "next_server_id", nextId
        )
        RetrofitManager.getInstance().api
            .getGameServers(filterQuery)
//                .map(RegionSettingHelper.filterGame)
//                .map(ApkActiveUtils.filterMapperList)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : BiResponse<ServerPublishEntity>() {
                override fun onSuccess(data: ServerPublishEntity) {
                    when (action) {
                        null -> {
                            prevId = data.prevId
                            nextId = data.nextId
                        }
                        "down" -> prevId = data.prevId
                        "up" -> nextId = data.nextId
                    }

                    if (action == "down") {
                        handlePrevData(data.data, action)
                    } else {
                        handleData(data.data, isRefresh, action)
                    }
                }

                override fun onFailure(exception: Exception) {
                    super.onFailure(exception)
                    loadStatusLiveData.postValue(Pair(action, LoadStatus.INIT_FAILED))
                }
            })
    }

    fun handleData(data: List<GameEntity>, isRefresh: Boolean, action: String?) {
        var i = 0
        val list = ArrayList(data)
        while (i < list.size) {

            // 初始化游戏状态
            val entity = list[i]
//            if (entity.serverRemaining != null) {
//                for (remainingGame in entity.serverRemaining!!) {
//                    remainingGame.sequence = mRealIndex++
//                }
//            }
//            entity.sequence = mRealIndex++
            entity.setEntryMap(DownloadManager.getInstance().getEntryMap(entity.name))
            ApkActiveUtils.filterHideApk(entity) // 过滤隐藏apk
            var fixedTopItem: GameEntity? = null

            // 当页面是由启动弹窗过来的第一或第二个页面的时候添加启动弹窗信息
            if (mEntrance.contains(EntranceConsts.ENTRANCE_WELCOME)
                && mEntrance.countOccurrences("+") <= 1
            ) {
                entity.setWelcomeDialogInfoIfAvailable()
            }

            // 设置置顶部分
            if (i == 0) {
                // 列表顶部，若有设置置顶应用就增加置顶头部
                if (isInit && entity.fixedTop!!) {
                    fixedTopItem = GameEntity()
                    fixedTopItem.fixedTopHint = true
                    fixedTopItem.fixedTop = true
                    list.add(i, fixedTopItem)
                    i++
                }
            }

            // 归零置顶游戏的开服时间避免找当前开服游戏时找到
            if (entity.fixedTop!!) {
                if (entity.serverEntity == null) {
                    val emptyCalendarEntity = ServerCalendarEntity()
                    emptyCalendarEntity.setTime(0)
                    entity.serverEntity = emptyCalendarEntity
                }
                entity.serverEntity!!.setTime(0)
            }

            //
            if (i == 0) {
                if (isInit) { // 列表page == 0 && position=0 默认添加时间断点
                    val kaiFuTimeEntity = GameEntity()
                    kaiFuTimeEntity.kaifuTimeHint = entity.serverEntity!!.getTime()
                    list.add(i, kaiFuTimeEntity)
                    i++
                } else { // 列表 page > 0 && position=0 与上一页最后一条对比
                    val gameEntity = listLiveData.value?.second?.last()
                    val serverEntity = gameEntity?.serverEntity
                    val nextServerEntity = entity.serverEntity
                    if (serverEntity == null || nextServerEntity == null) {
                        i++
                        continue
                    }
                    val time = serverEntity.getTime()
                    val nextTime = nextServerEntity.getTime()
                    if (time != nextTime) {
                        val kaiFuTimeEntity = GameEntity()
                        kaiFuTimeEntity.kaifuTimeHint = nextTime
                        list.add(i, kaiFuTimeEntity)
                        i++
                    }
                }
            }
            if (i < list.size - 1) {
                // 为置顶的项目添加第一个存在时间的游戏的开服时间
                if (fixedTopItem != null && fixedTopItem.kaifuTimeHint == null) {
                    fixedTopItem.kaifuTimeHint = entity.serverEntity!!.getTime()
                }
                val serverEntity = entity.serverEntity
                val nextServerEntity = list[i + 1].serverEntity
                if (serverEntity == null || nextServerEntity == null) {
                    i++
                    continue
                }
                val time = serverEntity.getTime()
                val nextTime = nextServerEntity.getTime()
                if (time != nextTime) {
                    val kaiFuTimeEntity = GameEntity()
                    kaiFuTimeEntity.kaifuTimeHint = nextTime
                    list.add(i + 1, kaiFuTimeEntity)
                    i++
                }
            }
            i++
        }

        val previousData = if (isRefresh) arrayListOf() else listLiveData.value?.second ?: arrayListOf()
        previousData.addAll(list)
        recordIndex(previousData)
        listLiveData.postValue(Triple(action, previousData, -1))
        initLocationMap(previousData)
        isInit = false

        when {
            list.size == 0 -> loadStatusLiveData.postValue(Pair(action, LoadStatus.INIT_EMPTY))
            data.size < 10 -> loadStatusLiveData.postValue(Pair(action, LoadStatus.INIT_OVER))
            else -> loadStatusLiveData.postValue(Pair(action, LoadStatus.INIT_LOADED))
        }
    }

    fun handlePrevData(data: List<GameEntity>, action: String?) {
        loadStatusLiveData.postValue(Pair(action, LoadStatus.INIT))
        var i = 0
        val list = ArrayList(data.reversed())
        while (i < list.size) {

            // 初始化游戏状态
            val entity = list[i]
//            if (entity.serverRemaining != null) {
//                for (remainingGame in entity.serverRemaining!!) {
//                    remainingGame.sequence = mRealIndex++
//                }
//            }
//            entity.sequence = mRealIndex++
            entity.setEntryMap(DownloadManager.getInstance().getEntryMap(entity.name))
            ApkActiveUtils.filterHideApk(entity) // 过滤隐藏apk
            var fixedTopItem: GameEntity? = null

            // 归零置顶游戏的开服时间避免找当前开服游戏时找到
            if (entity.fixedTop!!) {
                if (entity.serverEntity == null) {
                    val emptyCalendarEntity = ServerCalendarEntity()
                    emptyCalendarEntity.setTime(0)
                    entity.serverEntity = emptyCalendarEntity
                }
                entity.serverEntity!!.setTime(0)
            }

            // 设置时间断点
            if (i == 0) {
                // 列表 page > 0 && position=0 与下面页最开始一条对比
                val gameEntity = listLiveData.value?.second?.find { it.kaifuTimeHint != null }
                val serverEntity = gameEntity?.serverEntity
                val nextServerEntity = entity.serverEntity
                if (serverEntity != null && nextServerEntity != null) {
                    val time = serverEntity.getTime()
                    val nextTime = nextServerEntity.getTime()
                    if (time != nextTime) {
                        val kaiFuTimeEntity = GameEntity()
                        kaiFuTimeEntity.kaifuTimeHint = time
                        list.add(i, kaiFuTimeEntity)
                        i++
                    }
                }
            }

            if (i < list.size - 1) {
                // 为置顶的项目添加第一个存在时间的游戏的开服时间
                if (fixedTopItem != null && fixedTopItem.kaifuTimeHint == null) {
                    fixedTopItem.kaifuTimeHint = entity.serverEntity!!.getTime()
                }
                val serverEntity = entity.serverEntity
                val nextServerEntity = list[i + 1].serverEntity
                if (serverEntity == null || nextServerEntity == null) {
                    i++
                    continue
                }
                val time = serverEntity.getTime()
                val nextTime = nextServerEntity.getTime()
                if (time != nextTime) {
                    val kaiFuTimeEntity = GameEntity()
                    kaiFuTimeEntity.kaifuTimeHint = time
                    list.add(i + 1, kaiFuTimeEntity)
                    i++
                }
            }

            if (i == list.size - 1 && prevId?.isEmpty() == true) {
                val serverEntity = entity.serverEntity
                if (serverEntity == null) {
                    i++
                    continue
                }
                val kaiFuTimeEntity = GameEntity().apply {
                    kaifuTimeHint = serverEntity.getTime()
                }
                list.add(i + 1, kaiFuTimeEntity)
                i++
            }
            i++
        }

        val previousData = listLiveData.value?.second ?: arrayListOf()
        previousData.addAll(0, list.reversed())
        recordIndex(previousData)
        listLiveData.postValue(Triple(action, previousData, list.size))
        initLocationMap(previousData)

        when {
//            data.size < 20 -> loadStatusLiveData.postValue(Pair(action, LoadStatus.INIT_OVER))
            list.size == 0 -> loadStatusLiveData.postValue(Pair(action, LoadStatus.INIT_EMPTY))
            list.size > 0 -> loadStatusLiveData.postValue(Pair(action, LoadStatus.INIT_LOADED))
        }
    }

    fun mergerRemainingData(entity: GameEntity, position: Int) {
        val serverRemaining = entity.serverRemaining ?: return
        val entryMap = entity.getEntryMap()
        if (entryMap.isNotEmpty()) {
            serverRemaining.forEach {
                it.setEntryMap(entryMap)
            }
        }
        val previousData = listLiveData.value?.second ?: return
        previousData.addAll(position, serverRemaining)
        entity.serverRemaining = null
        initLocationMap(previousData)
        listLiveData.postValue(Triple(null, previousData, -1))
    }

    private fun initLocationMap(itemList: List<GameEntity>) {
        locationMap.clear()

        var list: ArrayList<Int>?
        var gameEntity: GameEntity
        var i = 0
        val size: Int = itemList.size
        while (i < size) {
            gameEntity = itemList[i]
            if (gameEntity.getApk().size != 0) {
                for ((packageName) in gameEntity.getApk()) {
                    list = locationMap[packageName]
                    if (list == null) {
                        list = java.util.ArrayList()
                        locationMap[packageName] = list
                    }
                    list.add(i)
                }
            }
            i++
        }
    }

    private fun recordIndex(list: ArrayList<GameEntity>) {
        var index = 0
        list.forEach {
            if (it.kaifuTimeHint != null) return@forEach
            it.sequence = index++
            if (it.serverRemaining != null) {
                for (remainingGame in it.serverRemaining!!) {
                    remainingGame.sequence = index++
                }
            }
        }
    }
}