package com.gh.gamecenter.gamedetail.fuli.kaifu

import android.annotation.SuppressLint
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.common.util.CheckLoginUtils
import com.gh.gamecenter.common.livedata.NonStickyMutableLiveData
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.throwExceptionInDebug
import com.gh.gamecenter.common.utils.toRequestBody
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.feature.entity.*
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.Single
import io.reactivex.SingleEmitter
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import java.text.SimpleDateFormat
import java.util.*

class ServersCalendarViewModel(
    application: Application,
    val game: GameEntity,
    val gameServer: GameDetailServer,
    var meEntity: MeEntity?,
) : AndroidViewModel(application) {

    val error = NonStickyMutableLiveData<Throwable>()

    val calendarLiveData: MutableLiveData<List<CalendarEntity>> = MutableLiveData()
    val serversDetailLiveData: MutableLiveData<CalendarEntity> = MutableLiveData()
    val serverCalendarLiveData: MutableLiveData<MutableList<ServerCalendarEntity>?> = MutableLiveData()
    val serverSubscriptionLiveData = MutableLiveData<ServerSubscriptionEntity?>()
    val subscribeServerSuccessEvent = MutableLiveData<Any?>()

    var monthCount = 0
    var curWeek = 0
    var curDay = 0

    var selectedMonth = MonthType.CUR_MONTH

    var isExistCurServer = true// 当月是否存在开服

    var kaifuCalendar: Calendar? = null

    init {
//        checkExistCurSerer()
        if (gameServer.status == "part") {
            loadServerData(true)
        } else {
            loadServerData(false)
        }

        // 登录状态下，且用户信息为空时尝试请求接口判断是否为兼职
        if (meEntity == null && CheckLoginUtils.isLogin()) {
            requestPartTimeInfo()
        }
    }

    /**
     * 设置选中的开服表日期
     * @param kaifuTime 选中日期的时间戳
     */
    fun setKaifuTime(kaifuTime: Long) {
        if (kaifuTime == 0L) return

        val currentCalendar = Calendar.getInstance().apply {
            set(Calendar.HOUR_OF_DAY, 0)
            set(Calendar.MINUTE, 0)
            set(Calendar.SECOND, 0)
            set(Calendar.MILLISECOND, 0)
        }

        val kaifuCalendar = Calendar.getInstance().also {
            this.kaifuCalendar = it
            it.timeInMillis = kaifuTime * 1000
        }
        val kaifuYear = kaifuCalendar.get(Calendar.YEAR)
        val kaifuMonth = kaifuCalendar.get(Calendar.MONTH)

        val currentYear = currentCalendar.get(Calendar.YEAR)
        val currentMonth = currentCalendar.get(Calendar.MONTH)

        this.selectedMonth = if (kaifuYear == currentYear && kaifuMonth == currentMonth - 1) {
            MonthType.PREVIOUS_MONTH
        } else if (kaifuYear == currentYear && kaifuMonth == currentMonth + 1) {
            MonthType.NEXT_MONTH
        } else {
            MonthType.CUR_MONTH
        }
    }

    @SuppressLint("CheckResult")
    fun loadServerData(isMirror: Boolean = false) {
        var apiService = RetrofitManager.getInstance().api
            .getGameServerCalendar(game.id, if (isMirror) "mirror" else "", true)

        if (!CheckLoginUtils.isLogin()) {
            serverSubscriptionLiveData.postValue(null)
        } else {
            apiService = RetrofitManager.getInstance().newApi
                .getServerSubscription(game.id)
                .onErrorReturnItem(ServerSubscriptionEntity())
                .zipWith(apiService) { subscription, list ->
                    serverSubscriptionLiveData.postValue(subscription)
                    list
                }
        }
        apiService
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                {
                    serverCalendarLiveData.postValue(it)
                },
                {
                    serverCalendarLiveData.postValue(null)
                }
            )
    }

    @SuppressLint("CheckResult")
    fun getServerSubscription(notifySubscribeSuccess: Boolean = false) {
        if (!CheckLoginUtils.isLogin()) {
            serverSubscriptionLiveData.postValue(null)
            return
        }

        // 已登录状态下检查开服表订阅状态
        RetrofitManager.getInstance().newApi
            .getServerSubscription(game.id)
            .onErrorReturnItem(ServerSubscriptionEntity())
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                {
                    serverSubscriptionLiveData.postValue(it)
                    if (notifySubscribeSuccess && it.byApp) {// 发送订阅成功通知
                        subscribeServerSuccessEvent.postValue(null)
                    }
                },
                {
                    serverSubscriptionLiveData.postValue(null)
                }
            )
    }

    @SuppressLint("CheckResult")
    fun subscribeServer() {
        RetrofitManager.getInstance().newApi
            .subscribeServer(game.id)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                {
                    getServerSubscription(true)
                },
                {
                    error.postValue(it)
                }
            )
    }

    @SuppressLint("CheckResult")
    fun unsubscribeServer() {
        RetrofitManager.getInstance().newApi
            .unsubscribeServer(game.id)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                {
                    getServerSubscription()
                }, {
                    error.postValue(it)
                }
            )
    }

    fun dispatchNotifySettingChange(id: String, notifySetting: ServerCalendarNotifySetting?) {
        val serverCalendarList = serverCalendarLiveData.value ?: return

        val index = serverCalendarList.indexOfFirst {
            it.id == id
        }

        if (index != -1) {
            val oldServerCalendar = serverCalendarList[index]
            val newServerCalendar = ServerCalendarEntity().apply {
                this.id = oldServerCalendar.id
                this.setTime(oldServerCalendar.getTime())
                this.setNote(oldServerCalendar.getNote())
                this.remark = oldServerCalendar.remark
                this.setFirstName(oldServerCalendar.getFirstName())
                this.setServerName(oldServerCalendar.getServerName())
                this.type = oldServerCalendar.type
                this.setDataMark(oldServerCalendar.getDataMark())
                this.notifySetting = notifySetting
            }
            serverCalendarList[index] = newServerCalendar
            serverCalendarLiveData.value = serverCalendarList
        }

    }

    @SuppressLint("CheckResult")
    private fun requestPartTimeInfo() {
        val requestMap = hashMapOf<String, List<String>>()
        requestMap["game"] = arrayListOf(game.id)

        RetrofitManager.getInstance().api.getUserRelatedInfoByPost(
            UserManager.getInstance().userId,
            requestMap.toRequestBody()
        )
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : BiResponse<UnifiedUserTrendEntity>() {
                override fun onSuccess(data: UnifiedUserTrendEntity) {
                    data.game?.let {
                        if (data.game.isNullOrEmpty()) return@let
                        for (game in it) {
                            meEntity = game.me
                            break
                        }
                    }
                }
            })
    }

//    private fun checkExistCurSerer() {
//        isExistCurServer = true // 此参数控制是否显示当月开服表（无论有没有开服信息），为防止需求变更先设死这个参数
//        val curDate = System.currentTimeMillis()
//        val formatMonth = SimpleDateFormat("MM", Locale.CHINA)
//        val curMonth = formatMonth.format(curDate).toInt()
//        for (kaiFuServerEntity in mServerList) { // 判断当月是否有开服
//            val time = kaiFuServerEntity.getTime()
//            val serverMonth = formatMonth.format(time * 1000).toInt()
//            if (serverMonth == curMonth) {
//                isExistCurServer = true
//                break
//            }
//        }
//    }

    @SuppressLint("CheckResult")
    fun initDate() {
        Single.create { emitter: SingleEmitter<MutableList<CalendarEntity>> ->
            val curDayData: MutableList<CalendarEntity> = ArrayList()
            // 获取当前 年-月
            val curDate = System.currentTimeMillis()
            val formatYear = SimpleDateFormat("yyyy", Locale.CHINA)
            val formatMonth = SimpleDateFormat("MM", Locale.CHINA)
            val formatDay = SimpleDateFormat("dd", Locale.CHINA)
            var curYear = formatYear.format(curDate).toInt()
            var curMonth = formatMonth.format(curDate).toInt()
            if (selectedMonth != MonthType.CUR_MONTH || !isExistCurServer) {
                if (selectedMonth == MonthType.PREVIOUS_MONTH) {
                    if (curMonth == 1) {
                        curMonth = 12
                        curYear--
                    } else {
                        curMonth -= 1
                    }
                } else {
                    selectedMonth = MonthType.NEXT_MONTH
                    if (curMonth == 12) {
                        curMonth = 1
                        curYear++
                    } else {
                        curMonth += 1
                    }
                }
            }

            curDay = formatDay.format(curDate).toInt()
            monthCount = getDaysByYearMonth(curYear, curMonth) // 获取当月天数
            curWeek = getWeekByDay(curYear, curMonth)
            /**
             * curWeek(当月一号的位置) 是以星期天开始算起，而当前日历是以星期一开始算，如果curWeek==1表明当月一号在星期天(理应在首位)
             * 　基于当前日历是以星期一开始算，应该加一个星期的数量补全位置　操蛋
             */
            if (curWeek == 1) {
                curWeek = 8
            }
            var day = 0
            for (i in 1..49) {
                val entity = CalendarEntity()
                if (i >= curWeek && monthCount > day) {
                    day++
                    entity.day = day
                    entity.month = curMonth
                    entity.year = curYear
                    curDayData.add(entity)
                } else {
                    entity.day = -1
                    curDayData.add(entity)
                }
            }
            if (curDayData[36].day == -1) {
                for (i in 1..7) {
                    curDayData.removeAt(49 - i)
                }
            }

            for (serverEntity in serverCalendarLiveData.value!!) {
                val time = serverEntity.getTime()
                val serverMonth = formatMonth.format(time * 1000).toInt()
                if (serverMonth == curMonth) {
                    val i = formatDay.format(time * 1000).toInt()
                    for (entity in curDayData) {
                        if (entity.day == i) {
                            val server = entity.server
                            server.add(serverEntity)
                            entity.server = server
                        }
                    }
                }
            }
            emitter.onSuccess(curDayData)
        }.subscribe(object : BiResponse<MutableList<CalendarEntity>>() {
            override fun onSuccess(data: MutableList<CalendarEntity>) {
                val kaifuCalendar = this@ServersCalendarViewModel.kaifuCalendar
                if (kaifuCalendar != null) {// 如果指定了选中的开服表日期，则自动唤起开服详情弹窗
                    val index = data.indexOfFirst {
                        it.year == kaifuCalendar.get(Calendar.YEAR)
                                && it.month == kaifuCalendar.get(Calendar.MONTH) + 1
                                && it.day == kaifuCalendar.get(Calendar.DATE)
                    }
                    if (index != -1) {
                        serversDetailLiveData.postValue(data[index])
                    }
                    this@ServersCalendarViewModel.kaifuCalendar = null
                }

                calendarLiveData.postValue(data)
            }

            override fun onFailure(exception: Exception) {
                super.onFailure(exception)
                throwExceptionInDebug("开服表日历初始化异常")
            }
        })
    }

    private fun getWeekByDay(year: Int, month: Int): Int {
        val calendar = Calendar.getInstance()
        calendar[Calendar.YEAR] = year
        calendar[Calendar.MONTH] = month - 1
        calendar[Calendar.DAY_OF_MONTH] = 1 //指定日
        return calendar[Calendar.DAY_OF_WEEK]
    }

    private fun getDaysByYearMonth(year: Int, month: Int): Int {
        val calendar = Calendar.getInstance()
        calendar[Calendar.YEAR] = year
        calendar[Calendar.MONTH] = month - 1
        calendar[Calendar.DATE] = 1
        calendar.roll(Calendar.DATE, -1)
        return calendar[Calendar.DATE]
    }

    fun getSelectTime(day: Int, month: Int, year: Int): Long {
        val calendar = Calendar.getInstance()
        calendar[Calendar.YEAR] = year
        calendar[Calendar.MONTH] = month - 1
        calendar[Calendar.DAY_OF_MONTH] = day
        return calendar.time.time
    }

    class Factory(
        private val mApplication: Application,
        private val mGame: GameEntity,
        private val mGameServer: GameDetailServer,
        private val mMeEntity: MeEntity?
    ) : ViewModelProvider.NewInstanceFactory() {
        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            return ServersCalendarViewModel(mApplication, mGame, mGameServer, mMeEntity) as T
        }
    }
}

enum class MonthType {
    CUR_MONTH,
    PREVIOUS_MONTH,
    NEXT_MONTH
}