-- 新商业化活动2 —— 7日任务
-- 逻辑：每天任务虽然不同，但是只要在活动结束前完成就可获得奖励，同类型任务共享进度。完成任务数量达到一定程度，可以获得额外奖励。
-- db
--[=[
    human.db.absAct[id] = 
    {
        taskList = {
            [taskId] = { --有进度的任务才存db
                progress = 0,
                isGet = nil,
            },
        },

        extraRewardRecord = {
            [1] = '1',  -- 领取了的额外奖励才存db
        },
    }

]=]--

local Msg = require("core.Msg")
local Grid = require("bag.Grid")
local Util = require("common.Util")
local Lang = require("common.Lang")
local BagLogic = require("bag.BagLogic")
local ObjHuman = require("core.ObjHuman")
local AbsActExcel = require("excel.absAct")
local Broadcast = require("broadcast.Broadcast")
local YunYingLogic = require("yunying.YunYingLogic")
local TriggerLogic = require("trigger.TriggerLogic")
local CycleActivityLogic = require("yunying.CycleActivity")
local actVariableCfg = require("excel.commercializationActivity").variable[1]
local sevenDayTaskCfg = require("excel.commercializationActivity").sevenDayTask
local Log = require("common.Log")


-- 本活动日志标识
local LOGTAG = "cycleAct_sevenDayTask"

-- 活动ID
local ACTID = 7301


local function getActBaseInfo(human, actId)
    local state, endTime, startTime = CycleActivityLogic.isStarted(human, actId)

    return state, endTime, startTime
end

local function initData(human, actId)
    local state, realEndTime = isOpen(human)
    if not state then
        return
    end

    human.db.absAct[actId] = human.db.absAct[actId] or {}
    human.db.absAct[actId].finish = realEndTime
end


local function getActData(human, actId)
    if not human.db.absAct[actId] then
        initData(human, actId)
    end
    return human.db.absAct[actId]
end

local function updateTaskData(human, actId, taskId, progress, isGet)
    local actData = getActData(human, actId)
    actData.taskList = actData.taskList or {}

    local taskList = actData.taskList
    taskList[taskId] = taskList[taskId] or {}

    if progress then
        taskList[taskId].progress = (taskList[taskId].progress or 0) + progress
    end

    if isGet then
        taskList[taskId].isGet = isGet
    end
end

local function updateExtraRewardData(human, actId, extraIdx)
    local actData = getActData(human, actId)
    actData.extraRewardRecord = actData.extraRewardRecord or {}

    actData.extraRewardRecord[extraIdx] = '1'
end



-- 计算当前是活动开启第几天
local function getActOPenDayIdx(human)
    local state, _, startTime = getActBaseInfo(human, ACTID)

    if not state then
        return 0
    end

    local dayStartTime = Util.getDayStartTime(startTime)
	local now = os.time()
	return math.ceil((now - dayStartTime + 1) / 24 / 3600)
end

-- 更新红点
local function updateRedDot(human)
    YunYingLogic.sendBanner(human)
    local otherConfig = AbsActExcel.absActivity[ACTID]
    YunYingLogic.sendGroupUpdate(YYInfo[ACTID], human, otherConfig.panelID)
end

-- 1 ~ 7天的红点标识数组
local function getRedDotArray(human)
    local redDotArray = {0, 0, 0, 0, 0, 0, 0}
    local actOpenDayIdx = getActOPenDayIdx(human)
    if actOpenDayIdx <= 0 then
        return redDotArray
    end

    local actData = getActData(human, ACTID)
    local taskListData = actData and actData.taskList
    if not taskListData then
        return redDotArray
    end

    for taskId, taskData in pairs(taskListData) do
        local taskCfg = sevenDayTaskCfg[taskId]
        if (not taskData.isGet and taskData.progress >= taskCfg.condValue) and taskCfg.dayIndx <= actOpenDayIdx then
            redDotArray[taskCfg.dayIndx] = 1
        end
    end

    return redDotArray
end

-- 是否完成所有任务
local function isCompleteAllTask(human, actId)
    local actData = getActData(human, actId)

    if not actData then
        return false
    end

    local taskListData = actData.taskList
    if not taskListData then
        return false
    end

    for taskId, taskCfg in ipairs(sevenDayTaskCfg) do
        if not taskListData[taskId] or taskListData[taskId].progress < taskCfg.condValue then
            return false
        end
    end

    return true
end

-- 统计已领取奖励的任务数量
local function calcGetRewardTaskNum(human)
    local actData = getActData(human, ACTID)

    if not actData then
        return 0
    end

    local taskListData = actData.taskList
    if not taskListData then
        return 0
    end

    local cnt = 0
    for taskId, taskData in pairs(taskListData) do
        if taskData.isGet then
            cnt = cnt + 1
        end
    end

    return cnt
end

--订阅事件
local function subscribeEvents(human, actId)
    local actData = getActData(human, actId)
    local taskList = actData.taskList or {}

    local registerTypeList = {}

    for taskId, taskCfg in ipairs(sevenDayTaskCfg)  do
        if not registerTypeList[taskCfg.eventType] and (not taskList[taskId] or taskList[taskId].progress < taskCfg.condValue) then
            TriggerLogic.SubscribeEvent(taskCfg.eventType, human.db._id, TaskActEventCBFunc)
            registerTypeList[taskCfg.eventType] = 1
        end
    end
end

-- 领取任务奖励
local function getTaskReward(human, dayIdx)
    local actOpenDayIdx = getActOPenDayIdx(human)
    if dayIdx <= 0 or dayIdx > actOpenDayIdx then
        return Broadcast.sendErr(human, Lang.YUNYING_ERR_TIME)
    end

    local actData = getActData(human, ACTID)
    local taskListData = actData.taskList
    if not taskListData then
        return Broadcast.sendErr(human, Lang.ABS_ANSWER_ITEM_IS_GET)
    end

    local len = 0
    local rewardList

    for taskId, taskData in pairs(taskListData) do
        local taskCfg = sevenDayTaskCfg[taskId]
        if taskCfg.dayIndx == dayIdx and taskData.progress >= taskCfg.condValue and not taskData.isGet then
            rewardList = rewardList or {}
            for _, itemCfg in ipairs(taskCfg.reward) do
                len = len + 1
                rewardList[len] = {itemCfg[1], itemCfg[2]}

                updateTaskData(human, ACTID, taskId, nil, true)
            end
        end
    end

    return rewardList
end

-- 领取额外奖励
local function getExtraReward(human)
    local actData = getActData(human, ACTID)
    if not actData.taskList then
        return Broadcast.sendErr(human, Lang.ABS_ANSWER_ITEM_IS_GET)
    end

    local completeTaskCnt = calcGetRewardTaskNum(human)
    if completeTaskCnt <= 0 then
        return Broadcast.sendErr(human, Lang.ABS_ANSWER_ITEM_IS_GET)
    end

    local len = 0
    local rewardList
    local extraRewardRecord = actData.extraRewardRecord
    for idx, targetTaskCnt in ipairs(actVariableCfg.va1) do
        if targetTaskCnt > completeTaskCnt then
            break
        end

        if not extraRewardRecord or not extraRewardRecord[idx] then
            rewardList = rewardList or {}
            local itemArrCfg = actVariableCfg.va2[idx]
            for _,itemCfg in pairs(itemArrCfg) do
                len = len + 1
                rewardList[len] = {itemCfg[1], itemCfg[2]}
            end

            updateExtraRewardData(human, ACTID, idx)
        end
    end

    return rewardList
end



--事件处理函数
function TaskActEventCBFunc(eventType, uuid, nValue1, nValue2)
    local human = ObjHuman.onlineUuid[uuid]
    if not human then
        return
    end

    local dayList
    local actOpenDayIdx = getActOPenDayIdx(human)
    local oldRedDotTag = isRed(human)

    local actData = getActData(human, ACTID)
    actData.taskList = actData.taskList or {}
    local taskList = actData.taskList

    for taskId, taskCfg in ipairs(sevenDayTaskCfg) do
        if taskCfg.eventType == eventType and (not taskList[taskId] or taskList[taskId].progress < taskCfg.condValue) then
            if taskCfg.condValueExtra <= 0 or (nValue2 and nValue2 >= taskCfg.condValueExtra) then
                updateTaskData(human, ACTID, taskId, nValue1)

                local dayIndx = taskCfg.dayIndx
                if dayIndx <= actOpenDayIdx and (not dayList or not dayList[dayIndx]) then
                    dayList = dayList or {}
                    dayList[dayIndx] = true
                end
            end
        end
    end

    --推数据给客户端更新
    if dayList then
        for dayIdx in pairs(dayList) do
            Query(human, dayIdx)
        end

        if oldRedDotTag ~= isRed(human) then
            updateRedDot(human)
        end
    end
end

-- 红点检测
function isRed(human, YYInfo, funcConfig)
    local actData = getActData(human, ACTID)
    if not actData or not actData.taskList then
        return false
    end

    local completeTaskNum = 0
    local taskListData = actData.taskList
    local actOpenDayIdx = getActOPenDayIdx(human)

    for taskId, taskData in pairs(taskListData) do
        local taskCfg = sevenDayTaskCfg[taskId]

        if taskCfg.condValue <= taskData.progress then
            if not taskData.isGet and actOpenDayIdx >= taskCfg.dayIndx then
                return true
            end

            if taskData.isGet then
                completeTaskNum = completeTaskNum + 1
            end
        end
    end

    local extraRewardRecord = actData.extraRewardRecord
    if completeTaskNum > 0 then
        local taskNumArr = actVariableCfg.va1
        for idx, needTaskNum in ipairs(taskNumArr) do
            if needTaskNum > completeTaskNum then
                break
            end

            if not extraRewardRecord or not extraRewardRecord[idx] then
                return true
            end
        end
    end

    return false
end

function isOpen(human, YYInfo, funcConfig)
    local state, endTime, startTime = getActBaseInfo(human, ACTID)
    if not state then return end

    return true, endTime, startTime
end

function isActive(human, YYInfo, funcConfig)
    return not isOpen(human, YYInfo, funcConfig)
end


function onLogin(human, funcID)
    if not isOpen(human) then
        return
    end

    if isCompleteAllTask(human, funcID) or human.sevenDayTaskRegister then
        return
    end

    subscribeEvents(human, funcID)

    human.sevenDayTaskRegister = true
end

function updateDaily(human, funcID)
    if not isOpen(human) then
        local logStr = string.format("CycleSevenDayTask Act is cannot Open, now: %d, playweNewUniqueTag: %s", os.time(), human.db.newUniqueTag)
        Log.write(Log.LOGID_OSS_COMMON_ACT, logStr)
        return
    end

    -- local actData = getActData(human, ACTID)
    -- if not actData then
    --     return
    -- end
    if not human.sevenDayTaskRegister and not isCompleteAllTask(human, ACTID) then
        subscribeEvents(human, funcID)
        human.sevenDayTaskRegister = true
    end

    local actOpenDayIdx = getActOPenDayIdx(human)
    Query(human, actOpenDayIdx)
end



function Query(human, dayIdx)
    if not isOpen(human) then
        return Broadcast.sendErr(human, Lang.YUNYING_ERR_TIME)
    end

    local actOpenDayIdx = getActOPenDayIdx(human)
    if dayIdx <= 0 or dayIdx > actOpenDayIdx then
        return Broadcast.sendErr(human, Lang.YUNYING_ERR_TIME)
    end

    local actData = getActData(human, ACTID)
    local completeTaskCnt = calcGetRewardTaskNum(human)

    local msgRet = Msg.gc.GC_CYCLESEVENDAYTASK_QUERY
    msgRet.dayIdx = dayIdx
    msgRet.completeTaskNum = completeTaskCnt

    local len = 0
    local taskList = msgRet.taskList
    local taskListData = actData.taskList

    for taskIdx, taskCfg in ipairs(sevenDayTaskCfg) do
        if dayIdx == taskCfg.dayIndx then
            len = len + 1
            taskList[len].taskIdx = taskIdx
            taskList[len].taskDesc = taskCfg.taskDesc
            taskList[len].taskState = 0
            taskList[len].taskNowProgress = 0
            taskList[len].taskCondProgress = taskCfg.condValue

            if taskListData and taskListData[taskIdx] then
                taskList[len].taskNowProgress = taskListData[taskIdx].progress

                if taskListData[taskIdx].progress >= taskCfg.condValue then
                    if taskListData[taskIdx].isGet then
                        taskList[len].taskState = 2
                    else
                        taskList[len].taskState = 1
                    end
                end
            end


            local taskRewardList = taskList[len].taskRewardList
            for idx, itemCfg in ipairs(taskCfg.reward) do
                taskRewardList[0] = idx
                Grid.makeItem(taskRewardList[idx], itemCfg[1], itemCfg[2])
            end
        end
    end
    taskList[0] = len

    -- 额外奖励
    local extraRewardList = msgRet.extraRewardList
    local extraRewardRecord = actData.extraRewardRecord

    for idx, targetTaskCnt in ipairs(actVariableCfg.va1) do
        extraRewardList[0] = idx
        extraRewardList[idx].condProgress = targetTaskCnt

        extraRewardList[idx].state = 0
        if completeTaskCnt >= targetTaskCnt then
            if extraRewardRecord and extraRewardRecord[idx] then
                extraRewardList[idx].state = 2
            else
                extraRewardList[idx].state = 1
            end
        end

        local itemCfg = actVariableCfg.va2[idx]
        Grid.makeItem(extraRewardList[idx].itemInfo, itemCfg[1][1], itemCfg[1][2])
    end

    local redDotArray = getRedDotArray(human)
    for idx, redTag in ipairs(redDotArray or {}) do
        msgRet.redDotArray[0] = idx
        msgRet.redDotArray[idx] = redTag
    end

    msgRet.openDay = getActOPenDayIdx(human)

    Msg.send(msgRet, human.fd)

    human.sevenDayTaskDayIdx = dayIdx
end

function GetReward(human, rewardType, idx)
    if not isOpen(human) then
        return Broadcast.sendErr(human, Lang.YUNYING_ERR_TIME)
    end

    local rewardList
    if rewardType == 1 then
        rewardList = getTaskReward(human, idx)
    elseif rewardType == 2 then
        rewardList = getExtraReward(human)
    else
        return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
    end

    if not rewardList then
        return Broadcast.sendErr(human, Lang.ABS_ANSWER_ITEM_IS_GET)
    end


    BagLogic.addItemList(human, rewardList, LOGTAG)

    Query(human, human.sevenDayTaskDayIdx)

    if not isRed(human) then
        updateRedDot(human)
    end
end