local ActBossRushData = class("ActBossRushData", BaseData)

local ACT_ID = 206
local PRO_ACT_ID = 130502
local UTRAL_ACT_ID = 130602

ActBossRushData.REWARD_TYPE = {
    FREE = 0,
    PRO = 1,
    UTRAL = 2
}

function ActBossRushData:clear()
    self.data.isDirty = false
    self.startTime = 0
    self.endTime = 0
    -- 战斗相关
    self.stageRandomSeed = 0
    self.stageList = {}
    self.todayMaxWave = 0
    self.todayFightCount = 0
    self.fightCount = 0
    self.todayMaxWaveRound = 0
    -- 兑换
    self.shop = {}
    -- 战令
    self.waveCount = 0                  -- 波次
    self.waveLevel = 0                  -- 波次等级 可领的最高等级
    self.freeLevel = 0                  -- 免费领取过的等级
    self.proLevel = 0                   -- 付费1领取过的等级
    self.utralLevel = 0                 -- 付费2领取过的等级
    self.free_awarded = {}              -- 领取过的免费id
    self.pay_low_awarded = {}           -- 领取过的付费1id
    self.pay_high_awarded = {}          -- 领取过的付费2id
    self.proBounght = false             -- 付费1已购买
    self.utralBounght = false           -- 付费2已购买
    self.waveLevelList = {}             -- 缓存波次等级
    self.waveLevelListCount = 0         -- 缓存最大等级
    -- 排行榜
    self.topRankList = {}
    self.lastRankList = {}
    self.rankList = {}
    self.selfRank = {}
    self.lastSelfRank = {}
    self.needUpdateRank = 0
    self.todayRankRerwardGot = false

    DataManager:unregisterCrossDayFunc("ActBossRushData")
end

function ActBossRushData:ctor()
    self:clear()
end

function ActBossRushData:setActivityInfo(activity)
    self.startTime = GFunc.formatTimeStep(activity.start_at)
    self.endTime = GFunc.formatTimeStep(activity.end_at)
end

function ActBossRushData:init(data)
    if not data then
        return
    end

    self.activity_id = data.activity_id
    self.bountyList = nil
    self.rankRewardList = nil
    -- 战斗
    if data.heroes then
        local update = false
        for _, heroId in ipairs(data.heroes) do
            if heroId > 0 then
                update = true
                break
            end
        end
        if update then
            DataManager.FormationData:initFormationByType(GConst.BattleConst.FORMATION_TYPE.BOSS_RUSH, data.heroes)
        end
    end
    self.todayFightCount = data.fight_count or 0
    self.fightCount = data.total_fight_count or 0
    self.todayMaxWave = data.max_wave or 0
    self.todayMaxWaveRound = data.min_round or 0

    -- 兑换
    self.shop = data.exchanged or {}

    -- 排行榜
    if data.rank_rewarded ~= nil then
        self.todayRankRerwardGot = data.rank_rewarded
    end

    -- 战令
    self.waveCount = data.accum_wave or 0
    self.waveLevelListCount = 0
    local list = self:getBountyList()
    local startId
    self.waveLevelStartId = nil
    for index, id in ipairs(list) do
        local info = self:getBountyCfg()[id]
        if info then
            self.waveLevelList[id] = info.exp
            self.waveLevelListCount = self.waveLevelListCount + 1
            if not startId or startId > id then
                startId = id
                self.waveLevelStartId = startId
            end
        end
    end
    if self.waveLevelStartId then
        local startId = math.max(0, self.waveLevelStartId - 1)
        self.freeLevel = startId
        self.proLevel = startId
        self.utralLevel = startId
    end

    if startId then
        for id = startId, startId + self.waveLevelListCount do
            local wave = self.waveLevelList[id]
            if wave and wave <= self.waveCount then
                self.waveLevel = id
            else
                break
            end
        end
    end

    if data.collected then
        for level, bossrushgrade in pairs(data.collected) do
            if bossrushgrade.normal then
                self:setFreeGot(level)
            end
            if bossrushgrade.superior then
                self:setProGot(level)
            end
            if bossrushgrade.superior_max then
                self:setUtralGot(level)
            end
        end
    end

    if data.bought ~= nil then
        self.proBounght = data.bought
        self.utralBounght = data.bought_max
    end

    DataManager:registerCrossDayFunc("ActBossRushData", function()
        self.todayMaxWave = 0
        self.todayMaxWaveRound = 0
        self.todayFightCount = 0

        self.needUpdateRank = 0
        self.todayRankRerwardGot = false
        self:setDirty()

        if self:getIsFirstDay() then
            EventManager:dispatchEvent(EventManager.CUSTOM_EVENT.MAIN_UI_CHECK_SIDE_BAR)
        end
    end)
end

function ActBossRushData:setDirty()
    self.data.isDirty = not self.data.isDirty
end

function ActBossRushData:getConditionDay()
    if not self.conditionDay then
        self.conditionDay = GFunc.getConstIntValue('activity_recurring_day')
        self.conditionDay = (self.conditionDay - 1) * 86400
    end

    return self.conditionDay
end

function ActBossRushData:getIsOpen()
    if GFunc.isShenhe() then
        self.isOpen = false
        return false
    end
    if not ModuleManager:getIsOpen(ModuleManager.MODULE_KEY.ACTIVITY, true) then
        self.isOpen = false
        return false
    end
    if Time:getServerTime() <= DataManager:getRegisterTs() + self:getConditionDay() then -- 前14天的号，看不到
        if self.fightCount > 0 or self.proBounght or self.utralBounght then
            -- 兼容已参与的玩家
        else
            self.isOpen = false
            return false
        end
    end
    local time = Time:getServerTime()
    local isOpen = false
    if self.endTime > time and time > self.startTime then
        isOpen = true
    end
    if self.isOpen == false and isOpen then -- 没开->开
        DataManager.BagData.ItemData:clearItemCount(GConst.ItemConst.ITEM_ID_BOSS_RUSH)
    end
    self.isOpen = isOpen
    return isOpen
end

function ActBossRushData:getRp()
    if not self:getIsOpen() then
        return false
    end

    if self:getHaveReward() then
        return true
    end

    if self:canGetRankReward() then
        return true
    end

    if not self:getTodayExchangeCheck() then
        return true
    end

    return false
end

function ActBossRushData:getRemainTime()
    local time = self.endTime - Time:getServerTime()
    if time < 0 then
        time = 0
    end
    return time
end

function ActBossRushData:getIsFinalDay()
    local time = self:getRemainTime()
    if time > 0 and time < 86400 then
        return true
    end
    return false
end

function ActBossRushData:getIsFirstDay()
    local time = Time:getServerTime() - self.startTime
    if time <= 86400 then
        return true
    end
    return false
end

---- 战斗
function ActBossRushData:updateStageSeed(seed)
    self.todayFightCount = self.todayFightCount + 1
    self.fightCount = self.fightCount + 1
    if self.stageRandomSeed == seed then
        return
    end
    self.stageRandomSeed = seed
    self.stageList = {}
    for id, info in ipairs(ConfigManager:getConfig("activity_boss_rush_chapter")) do
        table.insert(self.stageList, id)
    end
    self.stageList = table.shuffleBySeed(self.stageList, self.stageRandomSeed)
end

function ActBossRushData:getStageList()
    return self.stageList
end

function ActBossRushData:getTodayMaxWave()
    return self.todayMaxWave or 0
end

function ActBossRushData:getTodayFightCount()
    return self.todayFightCount
end

function ActBossRushData:getTotalFightCount()
    return self.fightCount
end

function ActBossRushData:getFreeFightLimit()
    if not self.freeFightLimit then
        self.freeFightLimit = GFunc.getConstIntValue("activity_boss_rush_time") or 1
    end
    return self.freeFightLimit
end

function ActBossRushData:getFreeFightCount()
    local count = self:getFreeFightLimit() - self:getTodayFightCount()
    if count < 0 then
        count = 0
    end
    return count
end

function ActBossRushData:getFightFree()
    return self.todayFightCount <= 0
end

function ActBossRushData:getFightCost()
    if not self.fightCostOrigin then
        self.fightCostOrigin = GFunc.getRewardNum(GFunc.getConstReward("activity_boss_rush_cost"))
        self.fightCostAdd = GFunc.getRewardNum(GFunc.getConstReward("activity_boss_rush_costadd"))
    end
    local count = self.todayFightCount - self:getFreeFightLimit()
    if count <= 0 then
        return self.fightCostOrigin
    end

    return self.fightCostOrigin + self.fightCostAdd * count
end


---- 排行榜
function ActBossRushData:getTodayRankList()
    if self:getRemainTime() < 86400 then -- 最后一天
        return self.lastRankList
    end
    return self.rankList
end

function ActBossRushData:getRankConfig()
    return ConfigManager:getConfig("activity_boss_rush_rank")
end

function ActBossRushData:getRankRewardList()
    if not self.rankRewardList then
        self.rankRewardList = {}
        local cfg = self:getRankConfig()
        for id, info in pairs(cfg) do
            if info.activity == (self.activity_id or ACT_ID) then
                table.insert(self.rankRewardList, id)
            end
        end
        table.sort(self.rankRewardList, function(a, b)
            return a < b
        end)
    end
    return self.rankRewardList
end

function ActBossRushData:getRankRewards(rank)
    if not rank or rank <= 0 then -- 没参加就没有
        return
    end
    if not self.cacheRankRewardsMap then -- 缓存名次对应的配置表ID
        self.cacheRankRewardsMap = {}
    end
    if not self.cacheRankRewardsMap[rank] then
        local cfg = self:getRankConfig()
        local lsit = self:getRankRewardList()
        for index, id in ipairs(lsit) do
            local info = cfg[id]
            if info.ranking[1] and info.ranking[2] then
                if info.ranking[1] <= rank and rank <= info.ranking[2] then
                    self.cacheRankRewardsMap[rank] = id
                end
            elseif info.ranking[1] then
                if info.ranking[1] <= rank then
                    self.cacheRankRewardsMap[rank] = id
                end
            end
        end
    end
    local cfg = self:getRankConfig()[self.cacheRankRewardsMap[rank]]
    if cfg then
        return cfg.reward
    end
end

function ActBossRushData:getNeedUpdateRank()
    if not self:getIsOpen() then
        return false
    end
    return (Time:getServerTime() - self.needUpdateRank) > 30
end

function ActBossRushData:setNeedUpdateRank()
    self.needUpdateRank = Time:getServerTime()
end

function ActBossRushData:updateRankInfo(info)
    self.lastRankList = info.yesterday_top50
    self.lastSelfRank = info.yesterday_self
    self.rankList = info.today_top50
    self.selfRank = info.today_self

    self.needUpdateRank = Time:getServerTime()
    self:setDirty()
end

function ActBossRushData:updateTopRankInfo(info)
    self.topRankList = info or {}

    self:setDirty()
end

function ActBossRushData:getTopRankInfo()
    return self.topRankList
end

function ActBossRushData:getLastRankInfo()
    return self.lastRankList
end

function ActBossRushData:getCurRankInfo()
    return self.rankList
end

function ActBossRushData:getLastSelfInfo()
    return self.lastSelfRank
end

function ActBossRushData:getCurRankSelfInfo()
    return self.selfRank
end

function ActBossRushData:canGetRankReward()
    if not self.todayRankRerwardGot then
        if (not self.lastSelfRank or not self.lastSelfRank.rank) and not self:getIsFirstDay() then
            return true
        end
    end

    if not self.lastSelfRank or not self.lastSelfRank.rank or self.lastSelfRank.rank <= 0 then
        return false
    end

    return not self.todayRankRerwardGot
end

function ActBossRushData:setGotRankReward()
    self.todayRankRerwardGot = true
    self:setDirty()
end

function ActBossRushData:isGotRankReward()
    return self.todayRankRerwardGot
end

---- 战令
function ActBossRushData:getBountyCfg()
    return ConfigManager:getConfig("activity_bounty_level")
end

function ActBossRushData:getBountyList()
    if not self.bountyList then
        self.bountyList = GFunc.getTable(DataManager:getActivityBountyLevelByActId(self.activity_id or ACT_ID) or {})
        table.sort(self.bountyList, function(a, b)
            return a < b
        end)
    end
    return self.bountyList
end

function ActBossRushData:getWaveCount()
    return self.waveCount or 0
end

function ActBossRushData:getWaveLevel()
    return self.waveLevel or 0
end

function ActBossRushData:getStartWaveLevel()
    return (self.waveLevelStartId - 1)
end

function ActBossRushData:getMaxLevel()
    return (self.waveLevelStartId - 1) + self.waveLevelListCount
end

function ActBossRushData:isMaxWaveLevel()
    return self.waveLevel >= self:getMaxLevel()
end

function ActBossRushData:getLevelWave(level)
    if level > self:getMaxLevel() then
        level = self:getMaxLevel()
    end
    return self.waveLevelList[level] or 0
end

function ActBossRushData:updateWaveAndRound(wave, round)
    self.waveNewtag = false
    self.roundNewtag = false
    if wave > self.todayMaxWave then
        self.todayMaxWave = wave
        self.todayMaxWaveRound = round
        self.waveNewtag = true
        self.roundNewtag = true
    elseif wave == self.todayMaxWave and round < self.todayMaxWaveRound then
        self.todayMaxWaveRound = round
        self.roundNewtag = true
    end
end

function ActBossRushData:getWaveRoundNewTag()
    return self.waveNewtag, self.roundNewtag
end

function ActBossRushData:getLastWaveLevelInfo()
    return self.lastWaveLevel or self.waveLevel, self.lastWaveCount or self.waveCount
end

function ActBossRushData:addWaveCount(count)
    self.lastWaveLevel = self.waveLevel
    self.lastWaveCount = self.waveCount

    self.waveCount = self.waveCount + count
    local nextLevel = self.waveLevel + 1
    if self.waveLevelList[nextLevel] and self.waveCount >= self.waveLevelList[nextLevel] then -- 升级了
        for id = nextLevel, self:getMaxLevel() do
            local wave = self.waveLevelList[id]
            if wave and wave <= self.waveCount then
                self.waveLevel = id
            else
                break
            end
        end
    end

    self:setDirty()
end

function ActBossRushData:getFreeGot(level)
    return self.free_awarded[level]
end

function ActBossRushData:setFreeGot(level)
    if not self.free_awarded[level] then
        self.freeLevel = self.freeLevel + 1
    end
    self.free_awarded[level] = true
end

function ActBossRushData:getProActId()
    return PRO_ACT_ID
end

function ActBossRushData:getProPrice()
    local cfg = ConfigManager:getConfig("act_gift")[PRO_ACT_ID]
    if not cfg then
        return GConst.EMPTY_STRING
    end
    return GFunc.getFormatPrice(cfg.recharge_id)
end

function ActBossRushData:getProGot(level)
    return self.pay_low_awarded[level]
end

function ActBossRushData:setProGot(level)
    if not self.pay_low_awarded[level] then
        self.proLevel = self.proLevel + 1
    end
    self.pay_low_awarded[level] = true
end

function ActBossRushData:getProBought()
    return self.proBounght
end

function ActBossRushData:setProBought()
    self.proBounght = true
    self:setDirty()
end

function ActBossRushData:getUtralActId()
    return UTRAL_ACT_ID
end

function ActBossRushData:gettUtralPrice()
    local cfg = ConfigManager:getConfig("act_gift")[UTRAL_ACT_ID]
    if not cfg then
        return GConst.EMPTY_STRING
    end
    return GFunc.getFormatPrice(cfg.recharge_id)
end

function ActBossRushData:getUtralGot(level)
    return self.pay_high_awarded[level]
end

function ActBossRushData:setUtralGot(level)
    if not self.pay_high_awarded[level] then
        self.utralLevel = self.utralLevel + 1
    end
    self.pay_high_awarded[level] = true
end

function ActBossRushData:getUtralBought()
    return self.utralBounght
end

function ActBossRushData:setUtralBought()
    self.utralBounght = true
    self:setDirty()
end

function ActBossRushData:gotFundReward(idWithLv)
    if not idWithLv then
        return
    end

    for _, info in ipairs(idWithLv) do
        if info.grade == 0 then
            self:setFreeGot(info.id)
        elseif info.grade == 1 then
            self:setProGot(info.id)
        elseif info.grade == 2 then
            self:setUtralGot(info.id)
        end
    end

    self:setDirty()
end

function ActBossRushData:gotSingleFundReward(level, grade)
    if grade == 0 then
        self:setFreeGot(level)
    elseif grade == 1 then
        self:setProGot(level)
    elseif grade == 2 then
        self:setUtralGot(level)
    end

    self:setDirty()
end

function ActBossRushData:getFreeCanGet(level)
    if self:getFreeGot(level) then
        return false
    end

    if self.waveLevel < level then
        return false
    end

    return true
end

function ActBossRushData:getProCanGet(level)
    if self:getProGot(level) then
        return false
    end

    if not self.proBounght then
        return false
    end

    if self.waveLevel < level then
        return false
    end

    return true
end

function ActBossRushData:getUtralCanGet(level)
    if self:getUtralGot(level) then
        return false
    end

    if not self.utralBounght then
        return false
    end

    if self.waveLevel < level then
        return false
    end

    return true
end

function ActBossRushData:getHaveReward()
    if self.freeLevel < self.waveLevel then
        return true
    end

    if self.proBounght then
        if self.proLevel < self.waveLevel then
            return true
        end
    end

    if self.utralBounght then
        if self.utralLevel < self.waveLevel then
            return true
        end
    end

    return false
end

function ActBossRushData:getReward(level, rewardType)
    local cfg = self:getBountyCfg()[level]
    if not cfg then
        return
    end

    if rewardType == ActBossRushData.REWARD_TYPE.FREE then
        return cfg.reward
    elseif rewardType == ActBossRushData.REWARD_TYPE.PRO then
        return cfg.reward_pro
    elseif rewardType == ActBossRushData.REWARD_TYPE.UTRAL then
        return cfg.reward_pro_max
    end
end

function ActBossRushData:getBuyBountyLevelCost()
    return GFunc.getConstReward("activity_bounty_cost")
end

---- 兑换商店

function ActBossRushData:getExchangeList()
    if not self.exchangeList then
        self.exchangeList = GFunc.getTable(DataManager:getActivityExchangeByActId(self.activity_id or ACT_ID) or {})
    end

    return self.exchangeList
end

function ActBossRushData:getExchangeConfig()
    return ConfigManager:getConfig("activity_exchange")
end

function ActBossRushData:getExchangeRemainCount(id)
    local count = self.shop[id] or 0
    local cfg = self:getExchangeConfig()[id]
    if not cfg then
        return 0
    end
    count = cfg.limit - count
    if count <= 0 then
        count = 0
    end
    return count
end

function ActBossRushData:getShopReward(id)
    local cfg = self:getExchangeConfig()[id]
    if not cfg then
        return
    end
    return cfg.reward
end

function ActBossRushData:getShopCost(id)
    local cfg = self:getExchangeConfig()[id]
    if not cfg then
        return
    end
    return cfg.cost
end

function ActBossRushData:setShopInfo(id, count)
    if not id or not count then
        return
    end
    self.shop[id] = (self.shop[id] or 0) + count
    self:setDirty()
end

function ActBossRushData:markPoped()
    self.popTag = true
end

function ActBossRushData:getMarkPoped()
    if self.popTag == nil then
        local time = LocalData:getNotPopToday("ActBossRushData")
        self.popTag = time == Time:getBeginningOfServerToday()
    end
    return self.popTag
end

function ActBossRushData:getTodayExchangeCheck()
    if self.todayExchangeChecked == nil then
        self.todayExchangeChecked = LocalData:getTodayBossRushExchangeWatched() == Time:getServerTime()
    end
    return self.todayExchangeChecked
end

function ActBossRushData:setTodayExchangeCheck()
    if self.todayExchangeChecked then
        return
    else
        LocalData:recordTodayBossRushExchangeWatched()
    end
    self.todayExchangeChecked = true
    self:setDirty()
end

return ActBossRushData