--在线奖励活动

--db
--[=[
    human.db.OnlineRewardData = {
        haveTime = nil,       --活动获得时间, 即首充时间
        dailyData = {       --每日数据,key为当前时间距离 haveTime 的天数
            [1] = {
                [1] = nil,  --记录当天某个档位奖励的领取情况, key 为档位，有记录表示已经领取了(不可领取和可领取两种状态不存db)
                [2] = nil,
            },
            [2] = {
                [1] = nil,
                [2] = nil,
            },
        }
    }
]=]--

local Msg = require("core.Msg")
local Grid = require("bag.Grid")
local Util = require("common.Util")
local BagLogic = require("bag.BagLogic")
local Broadcast = require("broadcast.Broadcast")
local Lang = require("common.Lang")
local onlineAardCfg = require("excel.onlineAward").onlineAward
local YunYingLogic = require("yunying.YunYingLogic")
local PanelDefine = require("broadcast.PanelDefine")
local Timer = require("core.Timer")
local ObjHuman = require("core.ObjHuman")


--分钟转秒
local TIMEBASE = 60

--一天的秒数
local DAYSEC = 86400

--本活动日志标识
local LOGTYPE = "OnlineAwardLogic"

--是否在线
-- IsOnline = false

--活动ID
local ACTID = 18001


--检查活动获得时间, 如果没有初始化则初始化
local function checkHaveTime(human)
    local OnlineRewardData = human.db.OnlineRewardData
    if not OnlineRewardData or not OnlineRewardData.haveTime then
        human.db.OnlineRewardData = human.db.OnlineRewardData or {}
        human.db.OnlineRewardData.haveTime = os.time()
    end
end

--计算当天到目前为止的总在线时长
local function calcTotalOnlineTime(human)
    local lastOnlineTime = human.db.onlineTimeDay or 0
    local loginTime = human.db.lastLoginTime

    --可能存在玩家在线跨天情况，需要判断登录时间与当前时间是否属于同一天，如果不是, 那么在此活动中，当天的登录时间应该为当天0点
    local now = os.time()
    if not Util.isSameDay(loginTime) then
        loginTime = Util.getDayStartTime(now)
    end

    local totalOnlineTime = now - loginTime + lastOnlineTime
    return totalOnlineTime
end

--获取当前时间距离startTime相差多少天
local function getDiffDay(startTime)
    local passDay = Util.diffDay(startTime) + 1
    return passDay
end

--是否获得该活动
local function isHaveAct(human)
    local topupAcount = human.db.topupAcount
    if topupAcount and topupAcount > 0 then
        return true
    end
    return false
end

--是否结束
local function isOver(human)
    local OnlineRewardData = human.db.OnlineRewardData
    if not OnlineRewardData then
        return false
    end

    local targetDay = getDiffDay(OnlineRewardData.haveTime)
    local targetCfg = onlineAardCfg[targetDay]
    --配置错误或者已经超过配置里的天数了都不显示
    if not targetCfg then
        return true
    end
    return false
end

--计算下一个未获得奖励需要的在线时间
local function calcLeftTime(human)
    local OnlineRewardData = human.db.OnlineRewardData
    local targetDay = getDiffDay(OnlineRewardData.haveTime)
    local targetCfg = onlineAardCfg[targetDay]

    if not targetCfg then
        return
    end

    local leftTime = 0
    local totalNeedTime = 0
    local timeCfg = targetCfg.onlineTimeVec
    local totalOnlineTime = calcTotalOnlineTime(human)

    for _, needTime in ipairs(timeCfg) do
        totalNeedTime = totalNeedTime + needTime * TIMEBASE
        if totalNeedTime > totalOnlineTime then
            leftTime = totalNeedTime - totalOnlineTime
            break
        end
    end
    return leftTime
end

--返回可领取奖励的index Vec
local function getCanReceiveAwardVec(human, isRed)
    local OnlineRewardData = human.db.OnlineRewardData
    local dailyData = OnlineRewardData.dailyData

    local targetDay = getDiffDay(OnlineRewardData.haveTime)
    local targetCfg = onlineAardCfg[targetDay]
    local todayRecordData = dailyData and dailyData[targetDay]

    if not targetCfg then
        if not isRed then
            Broadcast.sendErr(human, Lang.COMMON_COMFIG_ERROR)
        end
        return
    end

    --充值金额是否符合
    local topupAcountDaily = human.db.topupAcountDaily
    if not topupAcountDaily or topupAcountDaily < targetCfg.needRecharge then
        if not isRed then
            Broadcast.sendErr(human, Lang.COMMON_DAY_RECHARGE_NOT_ENOUGH)
        end
        return
    end

    local totalNeedTime = 0
    local cfgOnlineTimeVec = targetCfg.onlineTimeVec
    local totalOnlineTime = calcTotalOnlineTime(human)

    local len = 0
    local awardIdxVec = {}

    for idx, needTime in ipairs(cfgOnlineTimeVec) do
        totalNeedTime = totalNeedTime + needTime * TIMEBASE
        if totalOnlineTime >= totalNeedTime and (not todayRecordData or not todayRecordData[idx]) then
            len = len + 1
            awardIdxVec[len] = idx
        end
    end

    if len == 0 then
        return
    end
    return awardIdxVec
end

--定时器任务
local function timeFunc(human)
    if not ObjHuman.onlineNewUniqueTag[human.db.newUniqueTag] then
        return
    end
    -- if not IsOnline then
    --     return
    -- end

    local leftTime = calcLeftTime(human)
    if leftTime and leftTime > 0 then
        local now = os.time()
        local todayStartTi = Util.getDayStartTime(now)
        local nextDayStartTi = todayStartTi + DAYSEC

        --只有需要挂机时间 + 当前时间 < 下一天0点, 那么才加定时器
        if leftTime + now < nextDayStartTi then
            local tag = human.db.newUniqueTag
            Timer.addLater(leftTime, function ()
                local h = ObjHuman.onlineNewUniqueTag[tag]
                if not h then return end
                Query(h)
                --红点更新
                YunYingLogic.updateIcon(YYInfo[ACTID], h, true)
                timeFunc(h)
            end)
        end
    end
end


--红点判断
function isRed(human, YYInfo, funcConfig)
    if not isHaveAct(human) then
        return false
    end
    if not getCanReceiveAwardVec(human, true) then
        return false
    end
    return true
end


--是否开启(外部调用)
function isOpen(human)
    if not isHaveAct(human) then
        return false
    end

    if isOver(human) then
        return false
    end
    return true
end


--登录
function onLogin(human, actID)
    if not isHaveAct(human) then
        return
    end

    -- IsOnline = true

    checkHaveTime(human)

    timeFunc(human)
end

--下线
-- function onLogout(human, funcID, parameter, parameter2)
--     IsOnline = false
-- end

--跨天
-- function updateDaily(human, funcID)
--     checkHaveTime(human)
-- end

--新跨天函数，这里用新的跨天函数是因为ObjHuman.lua中 重置每日在线时间代码会晚于运营活动中的 updateDaily()执行
--这个活动中，会用到每日在线时间，所以需要重新定义一个跨天函数，在重置每日在线时间后再执行
function NewUpdateDaily(human)
    if not isHaveAct(human) then
        return
    end

    --if IsOnline then
        if isOver(human) then
            YunYingLogic.updateIcon(YYInfo[ACTID], human, true)
            return
        end

        --针对玩家在线跨天情况,下发一次最新数据
        Query(human)
        timeFunc(human)
    --end
end


--充值
function onCharge(human, price)
    local OnlineRewardData = human.db.OnlineRewardData
    if not OnlineRewardData or not OnlineRewardData.haveTime then
        checkHaveTime(human)
        timeFunc(human)
        YunYingLogic.updateIcon(YYInfo[ACTID], human, true)
    end

    OnlineRewardData = human.db.OnlineRewardData
    local targetDay = getDiffDay(OnlineRewardData.haveTime)
    local targetCfg = onlineAardCfg[targetDay]

    --活动结束后玩家充值导致报错
    if not targetCfg then
        return
    end

    local topupAcountDaily = human.db.topupAcountDaily
    if topupAcountDaily and topupAcountDaily >= targetCfg.needRecharge then
        Query(human)
    end

    return true
end


--查询
function Query(human)
    if not isHaveAct(human) then
        return Broadcast.sendErr(human, Lang.YUNYING_ERR_TIME)
    end

    local OnlineRewardData = human.db.OnlineRewardData
    local dailyData = OnlineRewardData.dailyData

    local targetDay = getDiffDay(OnlineRewardData.haveTime)
    local targetCfg = onlineAardCfg[targetDay]
    local todayData = dailyData and dailyData[targetDay]

    if not targetCfg then
        return Broadcast.sendErr(human, Lang.COMMON_COMFIG_ERROR)
    end

    local timeCfg = targetCfg.onlineTimeVec
    local awardCfg = targetCfg.awardVec

    if #timeCfg ~= #awardCfg then
        return Broadcast.sendErr(human, Lang.COMMON_COMFIG_ERROR)
    end

    local len = 0
    local totalNeedTime = 0
    local totalOnlineTime = calcTotalOnlineTime(human)

    local msgRet = Msg.gc.GC_ONLINEAWARD_QUERY
    msgRet.leftTime = 0
    msgRet.needRecharge = targetCfg.needRecharge
    msgRet.nowRecharge = human.db.topupAcountDaily or 0

    msgRet.isReach = 0
    local topupAcountDaily = human.db.topupAcountDaily
    if topupAcountDaily and topupAcountDaily >= targetCfg.needRecharge then
        msgRet.isReach = 1
    end

    msgRet.remainingDays = math.max(#onlineAardCfg - targetDay, 0)

    local msgAwardVec = msgRet.awardVec
    msgAwardVec[0] = 0

    for idx, needTime in ipairs(timeCfg) do
        len = len + 1
        msgAwardVec[len].state = 0
        Grid.makeItem(msgAwardVec[len].itemInfo, awardCfg[idx][1], awardCfg[idx][2])
        totalNeedTime = totalNeedTime + needTime * TIMEBASE
        if totalOnlineTime >= totalNeedTime then
            msgAwardVec[len].state = 1
            if todayData and todayData[idx] then
                msgAwardVec[len].state = 2
            end
        else
            if msgRet.leftTime == 0 then
                msgRet.leftTime = totalNeedTime - totalOnlineTime
            end
        end
    end
    msgAwardVec[0] = len

    Msg.send(msgRet, human.fd)
end


--领奖
function ClaimAward(human)
    if not isHaveAct(human) then
        return Broadcast.sendErr(human, Lang.YUNYING_ERR_TIME)
    end

    local awardIdxVec = getCanReceiveAwardVec(human)
    if not awardIdxVec then
        return
    end

    local OnlineRewardData = human.db.OnlineRewardData
    local targetDay = getDiffDay(OnlineRewardData.haveTime)

    OnlineRewardData.dailyData = OnlineRewardData.dailyData or {}
    OnlineRewardData.dailyData[targetDay] = OnlineRewardData.dailyData[targetDay] or {}
    local todayRecoedData = OnlineRewardData.dailyData[targetDay]

    local len = 0
    local awardVec = {}
    local targetCfg = onlineAardCfg[targetDay]
    local awardCfg = targetCfg.awardVec

    for _, idx in ipairs(awardIdxVec) do
        len = len + 1
        awardVec[len] = {awardCfg[idx][1], awardCfg[idx][2]}
        todayRecoedData[idx] = true
    end
    BagLogic.addItemList(human, awardVec, LOGTYPE)

    --下发数据更新
    Query(human)

    --红点更新
    YunYingLogic.updateIcon(YYInfo[ACTID], human, true)
end