package com.gamedog.vididin.manager.helpers

import com.ama.core.architecture.util.DateUtil
import com.ama.core.architecture.util.ResUtil
import com.ama.core.architecture.util.SpUtil
import com.ama.core.architecture.util.eventbus.NotifyMan
import com.viddin.videos.free.R
import com.gamedog.vididin.VididinEvents
import com.gamedog.vididin.beans.RECORD_CASH_PLUS_BOX_TASK
import com.gamedog.vididin.beans.RecordCash
import com.gamedog.vididin.core.login.login.AccountManager
import com.gamedog.vididin.main.fragments.task.BoxTaskRoot
import com.gamedog.vididin.manager.TaskManager
import com.gamedog.vididin.manager.TaskManager.Companion.BOX_SUB_TASK_TYPE_ZERO_BUY
import com.gamedog.vididin.manager.TaskManager.Companion.BOX_SUB_TASK_TYPE_SIGN
import com.gamedog.vididin.manager.TaskManager.Companion.BOX_SUB_TASK_TYPE_AD
import com.gamedog.vididin.manager.TaskManager.Companion.BOX_SUB_TASK_TYPE_VIDEO
import com.gamedog.vididin.manager.taskbeans.TaskStateBox
import com.gamedog.vididin.manager.taskbeans.TaskStateBoxRoot
import com.gamedog.vididin.manager.taskbeans.TaskStateBoxSub
import com.gamedog.vididin.manager.taskbeans.BaseTaskState.Companion.STATE_FINISH
import com.gamedog.vididin.manager.taskbeans.BaseTaskState.Companion.STATE_ONGOING
import com.gamedog.vididin.manager.taskbeans.BaseTaskState.Companion.STATE_CLAIMED
import com.gamedog.vididin.manager.taskbeans.BaseTaskState.Companion.STATE_EXPIRED


class BoxTaskHelper: BaseTaskHelper<TaskStateBoxRoot, BoxTaskRoot>() {

    override val mSpKey = SpUtil.KEY_TASK_BOX

    init {
        registerEvents( { eventData->
            when (eventData?.mEventType) {
                VididinEvents.EVENT_FINISHED_ONE_AD -> {
                    handleEvents(BOX_SUB_TASK_TYPE_AD)
                }

                VididinEvents.Event_Finish_One_Video -> {
                    handleEvents(BOX_SUB_TASK_TYPE_VIDEO)
                }

                VididinEvents.Event_Finish_One_Sign -> {
                    handleEvents(BOX_SUB_TASK_TYPE_SIGN)
                }

                VididinEvents.Event_Finish_One_Zerobuy -> {
                    handleEvents(BOX_SUB_TASK_TYPE_ZERO_BUY)
                }
            }

        }, VididinEvents.EVENT_FINISHED_ONE_AD, VididinEvents.Event_Finish_One_Video,
            VididinEvents.Event_Finish_One_Sign, VididinEvents.Event_Finish_One_Zerobuy)
    }

    override fun loadTaskFromSp() {
        val taskStateBeanInSp = SpUtil.instance().getObject<TaskStateBoxRoot>(mSpKey)
        if (taskStateBeanInSp == null || taskStateBeanInSp.boxList.isNullOrEmpty() || isAllBoxExpiredOrFinished(taskStateBeanInSp)) {
            mStateBean = generateStateBeanFromConfig()
            saveState2Sp()
        } else {
            mStateBean = taskStateBeanInSp
            calculateCurrentOngoingBox()
        }
    }

    private fun generateStateBeanFromConfig(): TaskStateBoxRoot {
        val boxStateList = mutableListOf<TaskStateBox>()
        mTaskConfig.chests.forEachIndexed { index, task ->
            val boxSubTaskStateList = mutableListOf<TaskStateBoxSub>()
            task.tasks.forEachIndexed { index, task ->
                boxSubTaskStateList.add(TaskStateBoxSub(task.task_id,
                    task.task_name, task.required_count, task.task_type))
            }

            boxStateList.add(TaskStateBox(task.chest_id, task.chest_name, task.duration_days,
                task.reward_type, task.reward_value, task.is_one_time, task.status,
                boxSubTaskStateList, DateUtil.getCurTimeMs()))
        }

        return TaskStateBoxRoot(boxStateList)
    }


    @Synchronized
    private fun handleEvents(taskType: Int) {
        val currentBoxIndex = getCurrentBoxIndex()
        if (!isBoxTasksFinished(currentBoxIndex)) {
            getCurrentBoxState()?.tasks?.forEachIndexed { index, subTask->
                if (taskType == subTask.task_type
                            && !isBoxSubTaskFinished(currentBoxIndex, index)) {
                    subTask.finishedNum++
                    saveState2Sp()
                    notifyEvent()
                }
            }
        }
        calculateCurrentOngoingBox()
    }

    private fun calculateCurrentOngoingBox() {
        mStateBean.boxList.forEachIndexed { index, box ->
            val curBoxStartMs = box.boxStartMs
            if (!DateUtil.isPeriodExpired(curBoxStartMs, box.duration_days)) {
                val stateEnum = getBoxStateEnum(index)
                if (stateEnum == STATE_ONGOING) {
                    if (mStateBean.currentBoxIndex != index) {
                        mStateBean.currentBoxIndex = index
                        mStateBean.boxList[index].boxStartMs = DateUtil.getCurTimeMs()
                        saveState2Sp()
                        notifyEvent()
                    }
                    return
                }
            }
        }
    }

    private fun notifyEvent() {
        NotifyMan.instance().sendEvent(VididinEvents.EVENT_BOX_TASK_STATE_CHANGED, null)
    }


    private fun isAllBoxExpiredOrFinished(taskStateBoxRoot: TaskStateBoxRoot): Boolean {
        return false
    }

    private fun isBoxTaskExpired(boxIndex: Int): Boolean {
        if (boxIndex >= 0 && boxIndex < mStateBean.boxList.size) {
            val curBoxState = mStateBean.boxList[boxIndex]
            return DateUtil.isPeriodExpired(curBoxState.boxStartMs, curBoxState.duration_days)
        }

        return false
    }

    private fun isBoxAllTasksFinish(boxIndex: Int) : Boolean {
        if (boxIndex >= 0 && boxIndex < mStateBean.boxList.size) {
            val curBoxState = mStateBean.boxList[boxIndex]

            curBoxState.tasks.forEach {
                if (it.required_count > it.finishedNum) {
                    return false
                }
            }
            return true
        }

        return false
    }

    fun getCurrentBoxIndex(): Int {
        return mStateBean.currentBoxIndex
    }

    fun getCurrentBoxState(): TaskStateBox? {
        val currentBoxIndex = getCurrentBoxIndex()

        if (currentBoxIndex >= 0 && currentBoxIndex < mStateBean.boxList.size) {
            return mStateBean.boxList[currentBoxIndex]
        }
        return null
    }

    fun getBoxState(boxIndex: Int): TaskStateBox? {
        if (boxIndex >= 0 && boxIndex < mStateBean.boxList.size) {
            return mStateBean.boxList[boxIndex]
        }
        return null
    }

    fun getCurrentBoxTotalDurationMs(): Long {
        return 1L * mStateBean.boxList[mStateBean.currentBoxIndex].duration_days * 24 * 3600000
    }

    fun getLeftValidBoxTotalDurationMs2(): Long {
        var totalLeftMs = 0L
        val currentBoxIndex = mStateBean.currentBoxIndex
        mStateBean.boxList.forEachIndexed { index, box ->
            if (currentBoxIndex == index) {
                totalLeftMs += (box.boxStartMs + box.duration_days * 24 * 3600000 - DateUtil.getCurTimeMs())
            }

            if (index > currentBoxIndex) {
                totalLeftMs += (box.duration_days * 24 * 3600000)
            }
        }
        return totalLeftMs
    }

    fun getLeftValidBoxTotalDurationStr(): String {
        val boxStatus = TaskManager.instance().boxTaskStatus()
        val leftMs = boxStatus.getCurrentBoxTotalDurationMs() + boxStatus.getCurrentBoxStartTimeMs() - DateUtil.getCurTimeMs()
        val boxLeftDays = leftMs / (24*3600000)
        val boxLeftHours = (leftMs - boxLeftDays * 24 * 3600000) / 3600000
        return boxLeftDays.toString() +  ResUtil.getString(R.string.day_simple)  + " " + boxLeftHours.toString( ) + ResUtil.getString(R.string.hour_simple)
    }

    fun getCurrentBoxStartTimeMs(): Long {
        return mStateBean.boxList[mStateBean.currentBoxIndex].boxStartMs
    }

    fun isBoxTasksFinished(boxIndex: Int) : Boolean {
        val stateEnum = getBoxStateEnum(boxIndex)
        return stateEnum == STATE_FINISH || stateEnum == STATE_CLAIMED
    }

    fun isAllBoxFinished(): Boolean {
        var isAllFinished = true
        for (index in 0..mStateBean.boxList.size - 1) {
            if (isBoxTasksFinished(index)) {
                isAllFinished = false
                break
            }
        }
        return isAllFinished
    }

    fun isBoxSubTaskFinished(boxIndex: Int, subTaskIndex: Int) : Boolean {
        val subTaskState = mStateBean.boxList[boxIndex].tasks[subTaskIndex]
        return subTaskState.finishedNum >= subTaskState.required_count
    }

    fun getBoxStateEnum(boxIndex: Int): Int {
        if (boxIndex >= 0 && boxIndex < mStateBean.boxList.size) {
            val curBoxState = mStateBean.boxList[boxIndex]

            if (curBoxState.hasClaimedReward) {
                return STATE_CLAIMED
            } else {
                if (isBoxAllTasksFinish(boxIndex)) {
                    return STATE_FINISH
                } else {
                    if (isBoxTaskExpired(boxIndex)) {
                        return STATE_EXPIRED
                    } else {
                        return STATE_ONGOING
                    }
                }
            }
        }
        return -1
    }

    fun getCouldClaimCashNum(): Double {
        var waitClaimCashNum = 0.0
        mStateBean.boxList.forEachIndexed { index, box ->
            if (getBoxStateEnum(index) == STATE_FINISH) {
                waitClaimCashNum += box.reward_value
            }
        }
        return waitClaimCashNum
    }

    fun getSubTaskHintStrRes(boxIndex: Int, subTaskIndex: Int): Int {
        when (boxIndex) {
            0-> {
                when (subTaskIndex) {
                    0-> {
                        return R.string.box_subtask_hint_1_1
                    }

                    1-> {
                        return R.string.box_subtask_hint_1_2
                    }

                    2-> {
                        return R.string.box_subtask_hint_1_3
                    }
                }
            }

            1-> {
                when (subTaskIndex) {
                    0-> {
                        return R.string.box_subtask_hint_2_1
                    }

                    1-> {
                        return R.string.box_subtask_hint_2_2
                    }

                    2-> {
                        return R.string.box_subtask_hint_2_3
                    }
                }
            }

            2-> {
                when (subTaskIndex) {
                    0-> {
                        return R.string.box_subtask_hint_3_1
                    }

                    1-> {
                        return R.string.box_subtask_hint_3_2
                    }

                    2-> {
                        return R.string.box_subtask_hint_3_3
                    }
                }
            }
        }

        return 0
    }

    fun getCurrentBoxTotalProgress(): Int {
        val currentBoxIndex = getCurrentBoxIndex()
        val boxList = mStateBean.boxList
        if (currentBoxIndex >= 0 && currentBoxIndex < boxList.size) {
            var totalFinished = 0
            var totalRequired = 0
            val currentBox = boxList[currentBoxIndex]

            currentBox.tasks.forEach {
                totalFinished += it.finishedNum
                totalRequired += it.required_count
            }

            if (totalRequired > 0) {
                val totalProgress = (100 * totalFinished) / totalRequired
                return if (totalProgress > 100) 100 else totalProgress
            }
        }
        return 0
    }

    fun executeClaimCash(): Boolean {
        try {
            val couldClaimCashNum = getCouldClaimCashNum()
            if (couldClaimCashNum > 0F) {
                AccountManager.adjustCash(couldClaimCashNum, RecordCash(RECORD_CASH_PLUS_BOX_TASK, couldClaimCashNum.toDouble()))
                mStateBean.boxList.forEachIndexed { index, box ->
                    if (getBoxStateEnum(index) == STATE_FINISH) {
                        box.hasClaimedReward = true
                    }
                }
                saveState2Sp()
                notifyEvent()
                return true
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return false
    }

}