local Config = require("Config")
local AbsActExcel = require("excel.absAct")
local Lang = require("common.Lang")
local Util = require("common.Util")
local Msg = require("core.Msg")
local AbsActDefine = require("absAct.AbsActDefine")
local PremiumGiftLogic = require("absAct.PremiumGiftLogic")
local ObjHuman = require("core.ObjHuman")
local Broadcast = require("broadcast.Broadcast")
local MangHeLogic = require("absAct.MangHeLogic")
local MailExcel = require("excel.mail")
local MailManager = require("mail.MailManager")
local HeroUpLogic = require("absAct.HeroUpLogic")
local CommonDB = require("common.CommonDB")
local DropExchangeLogic = require("absAct.DropExchangeLogic")
local PerpleHeroLogic = require("absAct.PerpleHeroLogic")
local HeroLogLogic = require("absAct.HeroLogLogic")
local AbsJifenDrawLogic = require("absAct.AbsJifenDrawLogic")
local HeroLoginPickLogic = require("absAct.HeroLoginPickLogic")
local AbsZhanbuLunpanLogic = require("absAct.AbsZhanbuLunpanLogic")
local DrawCardLogic = require("drawCard.DrawCardLogic")
local LimitPerpleHeroLogic = require("present.LimitPerpleHeroLogic")
local RechargeBackLogic = require("absAct.RechargeBackLogic")
local Abs365CardLogic = require("absAct.Abs365CardLogic")
local AbsWeeklyCardLogic = require("absAct.AbsWeeklyCardLogic")
local AbsSurpriseChest = require("absAct.AbsSurpriseChest")
local SpecialCustomLogic = require("absAct.SpecialCustomLogic")
local SevenDayLogic = require("absAct.SevenDayLogic")
local DrumBlastingLogic = require("absAct.DrumBlastingLogic")
local HeroComeLogic = require("absAct.HeroComeLogic")
local WishGiftLogic = require("absAct.WishGiftLogic")
local EveryDayPrayLogic = require("absAct.EveryDayPrayLogic")
local ExclusiveTaskLogic = require("absAct.ExclusiveTaskLogic")
local AbsActBillboardMiddleLogic = require("absAct.AbsActBillboardMiddleLogic")
local AbsActBillboardLogic = require("absAct.AbsActBillboardLogic")
local SingleReachLogic = require("absAct.SingleReachLogic")
local TotalReachLogic = require("absAct.TotalReachLogic")
local UseDiamondLogic = require("absAct.UseDiamondLogic")
local WishCupLogic = require("absAct.WishCupLogic")
local SeckillGiftLogic = require("absAct.SeckillGiftLogic")
local AbsOpenServerTotalConsume = require("absAct.AbsOpenServerTotalConsume")
local AbsReachRankLogic = require("absAct.AbsReachRankLogic")
local AbsReachRankDB = require("absAct.AbsReachRankDB")
local FestivalSevenDayCardLogic = require("absAct.FestivalSevenDayCardLogic")
local DailyFixedTaskLogic = require("absAct.DailyFixedTaskLogic")
local AbsSignGiftLogic = require("absAct.AbsSignGiftLogic")
local NewHeroLogic = require("absAct.NewHeroLogic")
local LotteryByDiamondLogic = require("absAct.LotteryByDiamondLogic")
local DuoBaoQiBingLogic = require("absAct.DuoBaoQiBingLogic")
local AbsLoginRewardLogic = require("absAct.AbsLoginRewardLogic")
local AbsDiscountStoreLogic = require("absAct.AbsDiscountStoreLogic")
local AbsLotteryCardLogic = require("absAct.AbsLotteryCardLogic")
local CycleActivityLogic = require("yunying.CycleActivity")

ABS_ACT_TYPE_LIST = nil
function initAfterHot()
    ABS_ACT_TYPE_LIST = {}
    local now = os.time()
    
    local len = 0
    for k, config in pairs(AbsActExcel.absActivity) do
        config.realStartTime = config.realStartTime or 0
        config.realEndTime = config.realEndTime or 0
        if next(config.startDate) and next(config.endDate) then 
            config.startDate.hour = 0
            config.startDate.min = 0
            config.startDate.sec = 0
            config.endDate.hour = 0
            config.endDate.min = 0
            config.endDate.sec = 0
            config.realStartTime = os.time(config.startDate)
            config.realEndTime = os.time(config.endDate)
        end
        ABS_ACT_TYPE_LIST[config.type] = ABS_ACT_TYPE_LIST[config.type] or {}
        ABS_ACT_TYPE_LIST[config.type][#ABS_ACT_TYPE_LIST[config.type] + 1] = k
    end
end

function onLogin(human)
    local sendLisg = {}
    local absActConfig = AbsActExcel.absActivity
    -- 清除过期活动
    for id in pairs(human.db.absAct) do
        checkAbsActClean(human,id)
    end
    -- 是否有新增活动
    for k,v in pairs(absActConfig) do 
        local ok,realEndTime, realStartTime = isStarted(human,k)
        if ok and  human.db.absAct[k] then
            --- 同步结束时间
            local nowTime = os.time()
            local finishTime = human.db.absAct[k].finish or nowTime
            if  finishTime >= nowTime and  finishTime ~= realEndTime then
                human.db.absAct[k].finish = realEndTime
            end

            if not human.db.absAct[k].realStartTime or human.db.absAct[k].realStartTime ~= realStartTime then
                human.db.absAct[k].realStartTime = realStartTime
            end
        end
        if ok and not human.db.absAct[k] then 
            human.db.absAct[k] = {}
            local f = load("return require(\"" .. v.moduleFn .. "\")")()
            if f and f.genAbsActData then 
                human.db.absAct[k] = f.genAbsActData(v, human)
            end
            human.db.absAct[k].finish = realEndTime -- 记录活动结束时间

            human.db.absAct[k].realStartTime = realStartTime
        end
    end
    -- 登录奖励重置
    for k, config in pairs(AbsActExcel.absLogin) do
        local state,id = isStartedByType(human,  config.absType)
        if state and id  then 
            if not human.db.absAct[id] then 
                human.db.absAct[id] = {}
            end 
            -- 每日登录领取
            if config.type == AbsActDefine.ABS_LOGIN_REWARD_TYPE_2 then
                local lastTime = human.db.absAct[id].loginDayGetTime or 0
                if not Util.isSameDay(lastTime) then
                    human.db.absAct[id].loginDayGetTime = os.time()
                    sendLisg[#sendLisg + 1] = k
                end
            end
        end
    end

    if #sendLisg > 0 then
        for _, id in ipairs(sendLisg) do
            local config = AbsActExcel.absLogin[id]
            if config.mailID > 0 then
               local mailConfig = MailExcel.mail[config.mailID]
               local title = mailConfig.title
               local senderName = mailConfig.senderName
               local content = mailConfig.content
               MailManager.add(MailManager.SYSTEM, human.db._id, title, content, config.item, senderName)	
            end
        end
    end
end

local function transTime(cfg)
    local realEndTime = 0
    local realStartTime = 0
    local state = false
    if next(cfg.startDate) and next(cfg.endDate) then
        cfg.startDate.hour = 0
        cfg.startDate.min = 0
        cfg.startDate.sec = 0
        cfg.endDate.hour = 0
        cfg.endDate.min = 0
        cfg.endDate.sec = 0
        realStartTime = os.time(cfg.startDate)
        realEndTime = os.time(cfg.endDate)
        state = true
    end
    return state, realEndTime, realStartTime
end

-- 判断活动是否开启
function isStarted(human, id)
	local Log = require("common.Log")
	local config = AbsActExcel.absActivity[id]
	if not config then 
		Log.write(Log.LOGID_DEBUG, "[isStarted] 配置不存在 - 活动ID: "..tostring(id))
		return 
	end

    local nNowOpenDay = CommonDB.getServerOpenDay()
    -- Log.write(Log.LOGID_DEBUG, "[isStarted] 开服天数检查 - 活动ID: "..tostring(id)..", 当前开服天数: "..tostring(nNowOpenDay)..", 需要开服天数: "..tostring(config.openDay))
    
    if nNowOpenDay < config.openDay then
        -- Log.write(Log.LOGID_DEBUG, "[isStarted] 开服天数不足 - 活动ID: "..tostring(id)..", 当前: "..tostring(nNowOpenDay)..", 需要: "..tostring(config.openDay))
        return
    end

    local _,realEndTime,realStartTime = transTime(config)
	local now = os.time()
	-- Log.write(Log.LOGID_DEBUG, "[isStarted] 时间检查 - 活动ID: "..tostring(id)..", 当前时间: "..tostring(now)..", 开始时间: "..tostring(realStartTime)..", 结束时间: "..tostring(realEndTime))
	
    if 0 == realEndTime or 0 == realStartTime then
        -- Log.write(Log.LOGID_DEBUG, "[isStarted] 时间为0,检查循环活动 - 活动ID: "..tostring(id))
       local nState, nEndTime, nBeginTime = CycleActivityLogic.isStarted(human, id)
    --    Log.write(Log.LOGID_DEBUG, "[isStarted] 循环活动检查结果 - 活动ID: "..tostring(id)..", 状态: "..tostring(nState)..", 开始: "..tostring(nBeginTime)..", 结束: "..tostring(nEndTime))
       
       if true == nState and 0 < nBeginTime and 0 < nEndTime then
            -- Log.write(Log.LOGID_DEBUG, "[isStarted] 循环活动判断通过 - 活动ID: "..tostring(id))
            return nState, nEndTime, nBeginTime
       else
            -- Log.write(Log.LOGID_DEBUG, "[isStarted] 循环活动判断失败 - 活动ID: "..tostring(id))
       end
    end

    if now < realStartTime or now >= realEndTime then
		--Log.write(Log.LOGID_DEBUG, "[isStarted] 不在活动时间内 - 活动ID: "..tostring(id)..", 当前: "..tostring(now)..", 开始: "..tostring(realStartTime)..", 结束: "..tostring(realEndTime))
		return
    end
    
    --Log.write(Log.LOGID_DEBUG, "[isStarted] 活动开启判断通过 - 活动ID: "..tostring(id))
    return true, realEndTime, realStartTime
end

-- 判断活动是否开启
function isStartedByType(human, type)
    if not ABS_ACT_TYPE_LIST[type] then return end

    for k, v in ipairs(ABS_ACT_TYPE_LIST[type]) do
        local config = AbsActExcel.absActivity[v]
        local ok , realEndTime,realStartTime = isStarted(human,v)
        if config and ok then
            return true, v, realEndTime, realStartTime
        end
    end
end

-- 根据actID 获取 Id
function getIDByActID(human, actID)
    for id, v in pairs(AbsActExcel.absActivity) do
        if v.actId == actID and isStarted(human, id) then
            return id
        end
    end
end

function getIsClearDB(actID)
    local config = AbsActExcel.absActivity[actID]
    if not config then
        return false
    end

    if config.type ~= AbsActDefine.ABS_ACT_TYPE_12 and config.type ~= AbsActDefine.ABS_ACT_TYPE_28 
            and config.type ~= AbsActDefine.ABS_ACT_TYPE_29 and config.type ~= AbsActDefine.ABS_ACT_TYPE_86 then
        return true
    else
        return false
    end
end

function checkAbsActClean(human, id)
    local config = AbsActExcel.absActivity[id]

    -- 活动没有配置 清楚对应数据
    if not config then
        print("[checkAbsActClean] 活动没有配置 清除对应数据 id = \n", id)
        human.db.absAct[id] = nil
        return
    end

    -- 不清理数据活动直接返回
    if AbsActDefine.ABS_ACT_NOCLEARID[config.type] == 1 then
        print("[checkAbsActClean] abs活动不清理活动数据直接返回 id = \n", id)
        return
    end

    local _,realEndTime = transTime(config)
    local now = os.time()

    --临时处理积分兑换 下版本删掉
    if  human.db.absAct[id] and not human.db.absAct[id].finish then
        if config.type ==  AbsActDefine.ABS_ACT_TYPE_7  then 
            human.db.absAct[id] = nil
        else
            human.db.absAct[id].finish = realEndTime
        end
    end
    if human.db.absAct[id] and now >= human.db.absAct[id].finish then
        -- 累计达标中的 累计充值到期 需要发送邮件
        if config.type ==  AbsActDefine.ABS_ACT_TYPE_71 then 
            --TotalReachLogic.clean(human,id)
        end
        --限时周卡，铂金周卡活动设定是即使活动结束也要让玩家领完奖励，所以这里活动结束后暂时不清除数据，在对应模块中做清除数据操作
        --古玉充能活动，活动后不清除数据

        -- if config.type ~= AbsActDefine.ABS_ACT_TYPE_12 and config.type ~= AbsActDefine.ABS_ACT_TYPE_28 
        --     and config.type ~= AbsActDefine.ABS_ACT_TYPE_29 then
        --     print("[checkAbsActClean] 清除数据 id = "..id)
        --     human.db.absAct[id] = nil
        -- end

        if getIsClearDB(id) then
            human.db.absAct[id] = nil
        end
    end
end

-- 活动详情查询
function actDetailQuery(human, id)
    local Log = require("common.Log")
    
    local config = AbsActExcel.absActivity[id]
    if config == nil then
        --Log.write(Log.LOGID_DEBUG, "[actDetailQuery] 配置不存在 - 玩家: "..tostring(human.db.name)..", 活动ID: "..tostring(id))
        return
    end
    
    -- 判断活动是否开启
    local startFlag, realEndTime, realStartTime = isStarted(human, id)
  
    if startFlag == nil then
        checkAbsActClean(human, id)
        return --Broadcast.sendErr(human, Lang.ACT_NOT_START)
    end

    -- 确保活动数据已初始化
    if not human.db.absAct[id] then
        human.db.absAct[id] = {}
        
        -- 尝试加载模块，添加错误处理
        local success, f = pcall(function()
            return load("return require(\"" .. config.moduleFn .. "\")")()
        end)
        
        if not success then
            -- 模块不存在，使用空数据继续
            human.db.absAct[id].finish = realEndTime
        elseif f and f.genAbsActData then
            human.db.absAct[id] = f.genAbsActData(config, human)
            human.db.absAct[id].finish = realEndTime -- 记录活动结束时间
        else
            human.db.absAct[id].finish = realEndTime
        end
    else
        --Log.write(Log.LOGID_DEBUG, "[actDetailQuery] 活动数据已存在 - 玩家: "..tostring(human.db.name)..", 活动ID: "..tostring(id))
    end

    if config.type == AbsActDefine.ABS_ACT_TYPE_1 then-- 超值礼包
        PremiumGiftLogic.getAndSendMsg(human, id, config.actId)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_2 then-- 盲盒
        MangHeLogic.query(human, id, config.actId)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_6 then
        DropExchangeLogic.query(human, id, true)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_4 then
        PerpleHeroLogic.getAndSendMsg(human,id)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_5 then
        HeroLogLogic.getAndSendMsg(human,id)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_7 then
        AbsJifenDrawLogic.getAndSendMsg(human, id, config)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_8 then
        HeroLoginPickLogic.query(human, id)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_9 then
        AbsZhanbuLunpanLogic.getAndSendMsg(human, id)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_10 then
        RechargeBackLogic.query(human, id)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_12 then
        AbsWeeklyCardLogic.getAndSendMsg(human, id, config)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_13 then
        Abs365CardLogic.getAndSendMsg(human, id, config)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_14 then
        AbsSurpriseChest.getAndSendMsg(human, id, config)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_18 then
        SevenDayLogic.getAndSendMsg(human, id, config.actID)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_16 then
        local success, err = pcall(function()
            DrumBlastingLogic.getAndSendMsg(human, id, config.actID)
        end)
        if not success then
            error(err)
        end
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_17 then
        SpecialCustomLogic.getAndSendMsg(human, id, config.actID)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_19 then
        HeroComeLogic.getAndSendMsg(human, id, config.actId)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_20 then
        WishGiftLogic.getAndSendMsg(human, id, config.actId)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_21 then
        EveryDayPrayLogic.getAndSendMsg(human, id, config.actId)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_22 then
        ExclusiveTaskLogic.getAndSendMsg(human, id, config.actId)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_26 then
        AbsReachRankLogic.getAndSendMsg(human, id)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_46 then
        AbsOpenServerTotalConsume.getAndSendMsg(human, id, config.actId)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_72 then
        SingleReachLogic.getAndSendMsg(human, id)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_71 then
        TotalReachLogic.getAndSendMsg(human, id)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_73 then
        AbsActBillboardLogic.getAndSendMsg(human, id)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_23 then
        SeckillGiftLogic.getAndSendMsg(human, id)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_24 then
        UseDiamondLogic.getAndSendMsg(human, id)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_25 then
        WishCupLogic.getAndSendMsg(human, id)
	elseif config.type == AbsActDefine.ABS_ACT_TYPE_27 then
        DailyFixedTaskLogic.getAndSendMsg(human, id)
	elseif config.type == AbsActDefine.ABS_ACT_TYPE_28 then
        FestivalSevenDayCardLogic.getAndSendMsg(human, id)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_29 then
        LotteryByDiamondLogic.Query(human, id)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_30 then
        AbsSignGiftLogic.getAndSendMsg(human, id)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_31 then
        DailyFixedTaskLogic.getAndSendMsg(human, id)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_32 then
        DuoBaoQiBingLogic.Query(human, id)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_33 then
        FestivalSevenDayCardLogic.getAndSendMsg(human, id)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_35 then
        NewHeroLogic.getAndSendMsg(human, id)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_75 then
        AbsLoginRewardLogic.Query(human, id)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_76 then
        AbsDiscountStoreLogic.Query(human, id)
    elseif config.type == AbsActDefine.ABS_ACT_TYPE_78 then
        AbsLotteryCardLogic.Query(human, id)
    end
end

-- 活动抽卡
function getLuckDraw(human,luckDraw,randomIndex,isAct,op)
    if isAct == AbsActDefine.OA_ACT_TYPE_501 then
        return LimitPerpleHeroLogic.getLuckDraw(human, op)
    end

    if not randomIndex then
        return 
    end

    if isAct == AbsActDefine.ABS_ACT_TYPE_3 then
        -- 判断活动是否存在
        local state,actID = isStartedByType(human, AbsActDefine.ABS_ACT_TYPE_3)
        -- 根据单抽十连抽判断是否中签
        if state then
            checkAbsActClean(human, actID)
            local actConfig = HeroUpLogic.getConfigByActID(actID)
            local randomNum = math.random(1,10000)
            if op == DrawCardLogic.DRAWCARD_OP_1 then
                if randomNum <= actConfig.singlePer then
                    luckDraw = true
                end
            elseif op == DrawCardLogic.DRAWCARD_OP_2 then
                if randomNum <= actConfig.tenPer and randomIndex then
                    luckDraw = true
                end
            end
        end

        if luckDraw then
            local actConfig = HeroUpLogic.getConfigByActID(actID)
            return actConfig.heroId
        end

    elseif isAct == AbsActDefine.ABS_ACT_TYPE_4 then
        -- 判断活动是否存在
        local state,actID = isStartedByType(human, AbsActDefine.ABS_ACT_TYPE_4)

        if state then
            checkAbsActClean(human, actID)
           
            local actConfig = PerpleHeroLogic.getConfigByActID(actID)
            local randomNum = math.random(1,10000)
            if randomNum <= actConfig.rate then
                luckDraw = true
            end
            local noTargetHeroCnt = human.db.absAct[actID].noTargetHeroCnt or 0
            if op == DrawCardLogic.DRAWCARD_OP_2 then
                noTargetHeroCnt = noTargetHeroCnt + 10
            else
                noTargetHeroCnt = noTargetHeroCnt + 1
            end

            human.db.absAct[actID].noTargetHeroCnt = noTargetHeroCnt

            if not luckDraw and noTargetHeroCnt >= actConfig.cnt then
                luckDraw = true
            end
           
            if luckDraw then 
                if human.db.absAct[actID] then
                    human.db.absAct[actID].noTargetHeroCnt = 0
                end
                return human.db.absAct[actID].perpleHero 
            end           
        end
    elseif isAct == AbsActDefine.ABS_ACT_TYPE_19 then
        -- 判断活动是否存在
        local state,actID = isStartedByType(human, AbsActDefine.ABS_ACT_TYPE_19)

        if state then
            checkAbsActClean(human, actID)
           
            local actConfig = HeroComeLogic.getConfigByActID(actID)
            local randomNum = math.random(1,10000)
            if randomNum <= actConfig.rate then
                luckDraw = true
            end
            local noTargetHeroCnt = human.db.absAct[actID].noTargetHeroCnt or 0
            if op == DrawCardLogic.DRAWCARD_OP_2 then
                noTargetHeroCnt = noTargetHeroCnt + 10
            else
                noTargetHeroCnt = noTargetHeroCnt + 1
            end

            human.db.absAct[actID].noTargetHeroCnt = noTargetHeroCnt

            if not luckDraw and noTargetHeroCnt >= actConfig.cnt then
                luckDraw = true
            end
           
            if luckDraw then 
                if human.db.absAct[actID] then
                    human.db.absAct[actID].noTargetHeroCnt = 0
                end
                return human.db.absAct[actID].perpleHero 
            end           
        end
    end
end

function onHour(hour)
    -- if hour == 23 then
    --     AbsActBillboardLogic.sendBillboardReward()
    -- end
    -- if hour == 1 then
    --     AbsActBillboardLogic.cleanBillBoardDB()
    -- end
end

function updateBillBoard(humanDb)
   if not humanDb.absAct then return end
   
   local now = os.time()
   
   for k, data in pairs(humanDb.absAct) do
      local config = AbsActExcel.absActivity[k]
      
      if config and config.type == AbsActDefine.ABS_ACT_TYPE_26 then
          AbsReachRankDB.loadBoardData(data, k, humanDb._id, now)
      end	
   end
end


function updateBillBoardRank()
   AbsReachRankDB.loadBoardRank()
end