package com.gh.gamecenter.servers.gametest2

import android.app.Application
import androidx.collection.ArrayMap
import androidx.collection.arrayMapOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.alibaba.android.arouter.launcher.ARouter
import com.gh.common.filter.RegionSettingHelper
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.constant.RouteConsts
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.observableToMain
import com.gh.gamecenter.common.utils.safelyGetInRelease
import com.gh.gamecenter.core.provider.IHandleGameResponseProvider
import com.gh.gamecenter.core.utils.TimeUtils
import com.gh.gamecenter.core.utils.UrlFilterUtils
import com.gh.gamecenter.entity.GameServerTestV2Entity
import com.gh.gamecenter.entity.ServerTestEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.Observable
import retrofit2.HttpException
import java.text.SimpleDateFormat
import java.util.*

class GameServerTestV2ListViewModel(
    application: Application,
    private val mGameServerTestV2ViewModel: GameServerTestV2ViewModel?
) : ListViewModel<ServerTestEntity.SliceData, GameServerTestV2ListViewModel.ItemData>(application) {

    var isLoadFirstPage = false
    val locationMap: ArrayMap<String, ArrayList<Int>> = arrayMapOf()
    private val mApi = RetrofitManager.getInstance().api
    private val mTimePositionArrayMap = ArrayMap<String, Int>()
    private val mCurrentPreviousAndNextWeeks = TimeUtils.getCurrentPreviousAndNextWeek()
    private val mTodayYesterdayAndTomorrowDate = TimeUtils.getTodayYesterdayAndTomorrow("MM.dd")

    override fun provideDataObservable(page: Int): Observable<MutableList<ServerTestEntity.SliceData>>? {
        return null
    }

    override fun load(loadType: LoadType?) {
        isLoadFirstPage = true
        mListLiveData.value = null
        mLoadStatusLiveData.postValue(LoadStatus.INIT_LOADING)
        val tabFilter = mGameServerTestV2ViewModel?.tabFilter?.value
        var categoryFilter = mGameServerTestV2ViewModel?.getCurrentSelectedCategoryFilterValue()?.value
        //如果选择全部类型，则传空值
        if (categoryFilter == GameServerTestV2ViewModel.GameCategory.ALL.value) {
            categoryFilter = ""
        }
        val filterQuery = UrlFilterUtils.getFilterQuery(
            "tab",
            tabFilter,
            "category",
            categoryFilter,
        )
        mApi.getServerTestV2(filterQuery)
            .compose(observableToMain())
            .subscribe(object : Response<GameServerTestV2Entity>() {
                override fun onResponse(response: GameServerTestV2Entity?) {
                    super.onResponse(response)
                    response?.let {
                        var index = 0
                        while (index < it.data.size) {
                            val slide = it.data[index]
                            // 推荐tab需要过滤掉既没有游戏大图也没有顶部视频的游戏
                            if (mGameServerTestV2ViewModel?.tabFilter == GameServerTestV2ViewModel.TestFilter.RECOMMEND) {
                                filterGameWithoutVideoAndImage(slide.gameList)
                            }
                            slide.gameList = RegionSettingHelper.filterGame(slide.gameList)
                            // 针对游戏的一些操作(过滤隐藏游戏，过滤隐藏APK，增加下载数据)
                            val handleGameResponse =
                                ARouter.getInstance().build(RouteConsts.provider.handleGameResponse)
                                    .navigation() as? IHandleGameResponseProvider
                            if (handleGameResponse != null) {
                                slide.gameList = handleGameResponse.handleGameResponse(
                                    slide.gameList,
                                    mEntrance
                                ) as ArrayList<GameEntity>
                            }
                            //对应日期下没有游戏时，则跳过不显示对应日期
                            if (slide.gameList.isEmpty()) {
                                it.data.remove(slide)
                            }
                            index++
                        }
                        loadStatusControl(it)
                        mListLiveData.postValue(it.data)
                    }
                }

                override fun onFailure(e: HttpException?) {
                    super.onFailure(e)
                    mLoadStatusLiveData.postValue(LoadStatus.INIT_FAILED)
                }
            })
    }

    private fun loadStatusControl(entity: GameServerTestV2Entity) {
        when {
            entity.data.isEmpty() -> {
                mLoadStatusLiveData.postValue(LoadStatus.INIT_EMPTY)
            }
            entity.data.isEmpty() -> {
                mLoadStatusLiveData.postValue(LoadStatus.INIT_OVER)
            }
            else -> {
                mLoadStatusLiveData.postValue(LoadStatus.INIT_LOADED)
            }
        }
    }

    override fun mergeResultLiveData() {
        mResultLiveData.addSource(mListLiveData) {
            transformData()
        }
    }

    private fun transformData() {
        val list = arrayListOf<ItemData>()
        val subList = arrayListOf<ItemData>()
        mTimePositionArrayMap.clear()

        for (slice in mListLiveData.value ?: listOf()) {
            subList.clear()

            var testTimeInHumanReadableFormat: String
            val sdf = SimpleDateFormat("MM.dd", Locale.CHINA)
            val day = mTodayYesterdayAndTomorrowDate.find { it.first == sdf.format(slice.testTime * 1000) }
            if (day != null && day.second in -1..1) {
                testTimeInHumanReadableFormat = when (day.second) {
                    -1 -> "昨天"
                    0 -> "今天"
                    else -> "明天"
                }
                testTimeInHumanReadableFormat = "${sdf.format(slice.testTime * 1000)} $testTimeInHumanReadableFormat"
            } else {
                testTimeInHumanReadableFormat = sdf.format(slice.testTime * 1000)
                val find = mCurrentPreviousAndNextWeeks.find { it.first == testTimeInHumanReadableFormat }
                if (find != null) {
                    testTimeInHumanReadableFormat = "$testTimeInHumanReadableFormat ${find.second}"
                }
            }

            val readableDaysOffset = when (slice.timeType) {
                "recent" -> GameServerTestV2ViewModel.TimeFilter.PAST_DAY.value
                "future" -> GameServerTestV2ViewModel.TimeFilter.UPCOMING_DAY.value
                else -> GameServerTestV2ViewModel.TimeFilter.TODAY.value
            }

            subList.add(
                ItemData(
                    time = testTimeInHumanReadableFormat,
                    testTime = slice.testTime,
                    readableDaysOffset = readableDaysOffset
                )
            )
            for ((index, game) in slice.gameList.withIndex()) {
                game.serverType = game.test?.type ?: game.serverType
                var brief: String
                //开测时间优先显示为 “昨天、今天、明天、周X、上周X、下周X”，超过“上周一-下周日”范围则显示“月份-日期”
                if (day != null && day.second in -1..1) {
                    brief = when (day.second) {
                        -1 -> "昨天"
                        0 -> "今天"
                        else -> "明天"
                    }
                } else {
                    brief = sdf.format(slice.testTime * 1000)
                    val find = mCurrentPreviousAndNextWeeks.find { it.first == brief }
                    if (find != null) {
                        brief = find.second
                    }
                }
                val isBigImage = mGameServerTestV2ViewModel?.tabFilter == GameServerTestV2ViewModel.TestFilter.RECOMMEND
                        && (readableDaysOffset == GameServerTestV2ViewModel.TimeFilter.TODAY.value
                        || readableDaysOffset == GameServerTestV2ViewModel.TimeFilter.UPCOMING_DAY.value)
                game.brief = if (isBigImage) {
                    game.recommendText
                } else {
                    val eventType = if (game.eventType == "test") "开启测试" else "首发上线"
                    "$brief ${TimeUtils.getFormatTime(game.time?.time ?: 0L, "HH:mm")} $eventType"
                }

                game.sequence = index
                game.testTime = sdf.format(slice.testTime * 1000)
                subList.add(
                    ItemData(
                        game = game,
                        testTime = slice.testTime,
                        readableDaysOffset = readableDaysOffset,
                        isTheLastOfTheLatestConsecutiveGame = index == slice.gameList.lastIndex,
                        isBigImage = isBigImage
                    )
                )
            }

            if (subList.size > 1) {
                val isCurrentDaysOffsetExist = mTimePositionArrayMap.getOrDefault(readableDaysOffset, 999) != 999
                if (!isCurrentDaysOffsetExist) {
                    mTimePositionArrayMap[readableDaysOffset] = list.size
                }
                list.addAll(subList)
            }
        }
        initLocationMap(list)
        mResultLiveData.postValue(list)
    }

    private fun filterGameWithoutVideoAndImage(list: ArrayList<GameEntity>) {
        var i = 0
        while (i < list.size) {
            val gameEntity = list[i]
            if (gameEntity.topVideo == null && gameEntity.homeSetting.image.isEmpty()) {
                list.removeAt(i)
                i--
            }
            i++
        }
    }

    private fun initLocationMap(itemList: ArrayList<ItemData>) {
        locationMap.clear()
        var list: ArrayList<Int>?
        var i = 0
        val size: Int = itemList.size
        while (i < size) {
            itemList[i].game?.let { gameEntity ->
                if (gameEntity.getApk().size != 0) {
                    for (apk in gameEntity.getApk()) {
                        list = locationMap[apk.packageName]
                        if (list == null) {
                            list = ArrayList()
                            locationMap[apk.packageName] = list
                        }
                        list?.add(i)
                    }
                }
            }
            i++
        }
    }

    fun getReadableDaysOffset(position: Int): String {
        return mResultLiveData.value?.safelyGetInRelease(position)?.readableDaysOffset ?: ""
    }

    fun getDayTextByPosition(position: Int): String {
        var dayText = ""
        val dataList = mResultLiveData.value

        dataList?.let {
            for ((index, value) in dataList.withIndex()) {
                if (value.time != null) {
                    dayText = value.time ?: ""
                }
                if (index == position) {
                    return dayText
                }
            }
        }
        return dayText
    }

    fun getItemAtPosition(position: Int): ItemData? {
        if (position < (mResultLiveData?.value?.size ?: 0)) {
            return mResultLiveData.value?.get(position)
        }
        return null
    }

    fun getPositionByTimeFilter(timeFilter: String): Int {
        val itemDataList = mResultLiveData.value ?: arrayListOf()
        var position = mTimePositionArrayMap.getOrDefault(timeFilter, -1)
        if (position >= 0) return position

        val recentCount =
            itemDataList.count { it.readableDaysOffset == GameServerTestV2ViewModel.TimeFilter.PAST_DAY.value }
        val todayCount =
            itemDataList.count { it.readableDaysOffset == GameServerTestV2ViewModel.TimeFilter.TODAY.value }

        when (timeFilter) {
            GameServerTestV2ViewModel.TimeFilter.PAST_DAY.value -> {
                position = mTimePositionArrayMap.getOrDefault(GameServerTestV2ViewModel.TimeFilter.TODAY.value, -1)
                if (position >= 0) return position
                position =
                    mTimePositionArrayMap.getOrDefault(GameServerTestV2ViewModel.TimeFilter.UPCOMING_DAY.value, -1)
                if (position >= 0) return position
            }
            GameServerTestV2ViewModel.TimeFilter.TODAY.value -> {
                position =
                    mTimePositionArrayMap.getOrDefault(GameServerTestV2ViewModel.TimeFilter.UPCOMING_DAY.value, -1)
                if (position >= 0) return position
                position =
                    mTimePositionArrayMap.getOrDefault(GameServerTestV2ViewModel.TimeFilter.PAST_DAY.value, -1)
                if (position >= 0) return recentCount - 1
            }
            GameServerTestV2ViewModel.TimeFilter.UPCOMING_DAY.value -> {
                position = mTimePositionArrayMap.getOrDefault(GameServerTestV2ViewModel.TimeFilter.TODAY.value, -1)
                if (position >= 0) return recentCount + todayCount - 1
                position =
                    mTimePositionArrayMap.getOrDefault(GameServerTestV2ViewModel.TimeFilter.PAST_DAY.value, -1)
                if (position >= 0) recentCount - 1
            }
        }

        return -1
    }

    class ItemData(
        var time: String? = null,
        var game: GameEntity? = null,
        var readableDaysOffset: String = "",
        var testTime: Long = 0,
        var isTheLastOfTheLatestConsecutiveGame: Boolean = false,
        var isBigImage: Boolean = false
    )

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

}