local TournArenaData = class("TournArenaData", BaseData)

function TournArenaData:ctor()
    self.data.isDirty = false

    self.bountyLevel = 1
    self.bountyExp = 0
    self.bountyCollected = {}
    self.rankStep = 1
    self.rankStepEndTime = 0
    self.rankCollected = {}
end

function TournArenaData:clear()
    DataManager:unregisterTryOpenFunc("TournArenaData")
    DataManager:unregisterCrossDayFunc("TournArenaData")
end

-- 设置活动数据
function TournArenaData:setActStatus(data)
    data = data or GConst.EMPTY_TABLE

    self.actId = data.id
    self.startTime = GFunc.formatTimeStep(data.start_at)
    self.endTime = GFunc.formatTimeStep(data.end_at)

    if EDITOR_MODE then
        Logger.logHighlight("竞技场锦标赛活动开启时间：")
        Logger.printTable(data)
    end

    if not self:isOpen() then
        -- 活动开启
        DataManager:registerTryOpenFunc("TournArenaData", function()
            if not self:isOpen() then
                return
            end
            if not self:isActiveTime() then
                return
            end

            DataManager:unregisterTryOpenFunc("TournArenaData")
            ModuleManager.TournArenaManager:reqActData()
        end)
    end
end

-- 获取活动数据成功
function TournArenaData:onGetActData(data)
    data = data or GConst.EMPTY_TABLE
    if EDITOR_MODE then
        Logger.logHighlight("竞技场锦标赛活动数据：")
        Logger.printTable(data)
    end

    -- 战令
    self.bountyLevel = data.level or 1
    self.bountyExp = data.exp or 0
    self.bountyCollected = data.collected or {}
    -- 排行榜
    self.rankStep = data.present_turn or 1
    self.rankStepEndTime = GFunc.formatTimeStep(data.turn_end_at) or 0
    self.rankCollected = data.rank_reward_claimed or {}

    -- 跨天
    DataManager:registerCrossDayFunc("TournArenaData", function()
        if not self:isOpen() then
            return
        end
        if not self:isActiveTime() then
            return
        end

        self.rankStep = self:isFinalDay() and 0 or self.rankStep + 1
        self.rankStepEndTime = self:isFinalDay() and -1 or (self.rankStepEndTime + 86400 * 2)
        self.ranks = nil
        self:setInReset(true)
        self:setDirty()
    end)

    self:setDirty()
end

function TournArenaData:setInReset(isInReset)
	self.isInReset = isInReset
end

function TournArenaData:getIsInReset()
	return self.isInReset
end

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

function TournArenaData:isOpen()
    if GFunc.isShenhe() then
        return false
    end
    if not ModuleManager:getIsOpen(ModuleManager.MODULE_KEY.ACTIVITY, true) then
        return false
    end
    if Time:getServerTime() <= DataManager:getRegisterTs() + self:getConditionDay() then -- 前14天的号，看不到
        return false
    end
    return true
end

-- 是否在活动配置时间内
function TournArenaData:isActiveTime()
    if self.startTime == nil or self.startTime <= 0 then
        return false
    end
    if self.endTime == nil or self.endTime <= 0 then
        return false
    end
    return Time:getServerTime() >= self.startTime and Time:getServerTime() <= self.endTime
end

-- 获取活动开启剩余时间（秒）
function TournArenaData:getStartRemainTime()
    if self.startTime == nil or self.startTime <= 0 then
        return 0
    end
    return self.startTime - Time:getServerTime()
end

-- 获取活动结束剩余时间（秒）
function TournArenaData:getEndRemainTime()
    if self.endTime == nil or self.endTime <= 0 then
        return 0
    end
    return self.endTime - Time:getServerTime()
end

-- 是否是活动最后一天
function TournArenaData:isFinalDay()
    return self:getEndRemainTime() <= 86400
end

-- 当前为活动第几天
function TournArenaData:getActDay()
    local days = Time:getDistanceDays(self.startTime)
    if days < 0 then
        days = -days
    end
    return days + 1
end

function TournArenaData: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 TournArenaData:hasEntryRedPoint()
    return self:hasBountyRedPoint() or self:hasRankRedPoint() or self:hasGiftRedPoint()
end

-- 战令--------------------------------------------------------------------------------------------------

-- 是否有战令红点
function TournArenaData:hasBountyRedPoint()
    if self:getFirstCanGetBountyRewardLevel() ~= nil then
        return true
    end

    return false
end

-- 获取首个可领取奖励的战令等级
function TournArenaData:getFirstCanGetBountyRewardLevel()
    local curLevel = self:getBountyLevel()

    for level, data in ipairs(self:getBountyIdList()) do
        if level > curLevel then
            break
        end

        if self:canGetBountyReward(level, GConst.TournArenaConst.BOUNTY_GRADE_TYPE.FREE) then
            return true
        end
        if self:canGetBountyReward(level, GConst.TournArenaConst.BOUNTY_GRADE_TYPE.PAY1) then
            return true
        end
        if self:canGetBountyReward(level, GConst.TournArenaConst.BOUNTY_GRADE_TYPE.PAY2) then
            return true
        end
    end

    return nil
end

-- <level,id>
function TournArenaData:getBountyIdList()
    if not self.bountyIdList then
        self.bountyIdList = GFunc.getTable(DataManager:getActivityBountyLevelByActId(self.actId) or {})
        table.sort(self.bountyIdList, function(a, b)
            return a < b
        end)
    end
    return self.bountyIdList
end

-- 获取对应等级的配置
function TournArenaData:getBountyCfgByLevel(level)
    return ConfigManager:getConfig("activity_bounty_level")[self:getBountyIdList()[level]]
end

-- 获取战令档位礼包配置
function TournArenaData:getBountyGradeGiftCfg(gradeType)
    if gradeType == GConst.TournArenaConst.BOUNTY_GRADE_TYPE.PAY1 then
        return DataManager.ShopData:getActGiftConfig()[GConst.TournArenaConst.BOUNTY_GIFT_ID_1]
    elseif gradeType == GConst.TournArenaConst.BOUNTY_GRADE_TYPE.PAY2 then
        return DataManager.ShopData:getActGiftConfig()[GConst.TournArenaConst.BOUNTY_GIFT_ID_2]
    end
end

-- 战令档位是否已解锁
function TournArenaData:isBountyGradeUnlock(grade)
    local giftId
    if grade == GConst.TournArenaConst.BOUNTY_GRADE_TYPE.FREE then
        return true
    elseif grade == GConst.TournArenaConst.BOUNTY_GRADE_TYPE.PAY1 then
        giftId = GConst.TournArenaConst.BOUNTY_GIFT_ID_1
    elseif grade == GConst.TournArenaConst.BOUNTY_GRADE_TYPE.PAY2 then
        giftId = GConst.TournArenaConst.BOUNTY_GIFT_ID_2
    end

    local giftData = DataManager.ShopData:getActGiftDetailData(PayManager.PURCHARSE_TYPE.ACT_GIFT, giftId)
    if giftData and giftData.buy_count > 0 and giftData.latest_buy_at then
        local time = giftData.latest_buy_at // 1000
        if time > self.startTime and time < self.endTime then
            return true
        end
    end
    return false
end

-- 战令最大等级
function TournArenaData:getBountyMaxLevel()
    return #self:getBountyIdList()
end

-- 获取当前战令等级
function TournArenaData:getBountyLevel()
    if self.bountyLevel <= self:getBountyMaxLevel() then
        return self.bountyLevel
    else
        return self:getBountyMaxLevel()
    end
end

-- 获取当前等级战令积分
function TournArenaData:getBountyLevelScore()
    return self.bountyExp
end

-- 获取当前总积分
function TournArenaData:getBountyTotalScore()
    return self:getBountyLevelScore() + (self:getBountyCfgByLevel(self:getBountyLevel()).exp or 0)
end

-- 获取等级所需总积分
function TournArenaData:getLevelTotalScore(level)
    local cfg = self:getBountyCfgByLevel(level)
    return cfg and cfg.exp or 0
end

-- 是否满足购买战令等级的条件
function TournArenaData:canBuyBountyLevel()
    if self:getBountyLevel() >= self:getBountyMaxLevel() then
        return false
    end

    local intervalDay = Time:getDistanceDays(self.endTime)
    if intervalDay < 0 then
        intervalDay = -intervalDay
    end
    return intervalDay <= 1
end

-- 购买战令等级的消耗
function TournArenaData:getBuyBountyLevelCost()
    return GFunc.getConstReward("activity_bounty_cost")
end

-- 获取战令档位奖励
function TournArenaData:getBountyGradeReward(level, grade)
    local cfg = self:getBountyCfgByLevel(level)
    local result
    if cfg then
        if grade == GConst.TournArenaConst.BOUNTY_GRADE_TYPE.FREE then
            result = cfg.reward
        elseif grade == GConst.TournArenaConst.BOUNTY_GRADE_TYPE.PAY1 then
            result = cfg.reward_pro
        elseif grade == GConst.TournArenaConst.BOUNTY_GRADE_TYPE.PAY2 then
            result = cfg.reward_pro_max
        end
    end
    return result
end

-- 战令奖励可领取
function TournArenaData:canGetBountyReward(level, grade)
    return self:isReachBountyReward(level, grade) and not self:isReceivedBountyReward(level, grade)
end

-- 战令奖励是否满足领取条件
function TournArenaData:isReachBountyReward(level, grade)
    local curLevel = self:getBountyLevel()
    if curLevel >= level then
        return self:isBountyGradeUnlock(grade)
    else
        return false
    end
end

-- 战令奖励是否已领取
function TournArenaData:isReceivedBountyReward(level, grade)
    local id = self:getBountyIdList()[level]
    if self.bountyCollected[id] == nil then
        return false
    end

    if grade == GConst.TournArenaConst.BOUNTY_GRADE_TYPE.FREE then
        return self.bountyCollected[id].normal
    elseif grade == GConst.TournArenaConst.BOUNTY_GRADE_TYPE.PAY1 then
        return self.bountyCollected[id].superior
    elseif grade == GConst.TournArenaConst.BOUNTY_GRADE_TYPE.PAY2 then
        return self.bountyCollected[id].superior_max
    end
end

-- 获取奖励档位收集进度
function TournArenaData:getBountyProgress(level)
    local cur = self:getBountyTotalScore()
    local rangeMin = self:getBountyLevelRangeMin(level)
    local rangeMax = self:getBountyLevelRangeMax(level)
    -- Logger.logHighlight(level.."范围:"..rangeMin.."->"..rangeMax)

    if cur >= rangeMax then
        -- 超过进度条
        return 1
    elseif cur < rangeMin then
        --低于进度条
        return -1
    elseif cur == rangeMin then
        -- 进度最低值
        return 0
    else
        -- 在进度条范围内
        return (cur - rangeMin) / (rangeMax - rangeMin)
    end
end

-- 获取档位范围最低值
function TournArenaData:getBountyLevelRangeMin(level)
    local rangeMin = 0
    local curScore = self:getLevelTotalScore(level)
    local lastScore = self:getLevelTotalScore(level - 1)
    if lastScore > 0 then
        rangeMin = curScore - math.floor((curScore - lastScore) / 2)
    else
        rangeMin = curScore / 2
    end
    return rangeMin
end

-- 获取档位范围最高值
function TournArenaData:getBountyLevelRangeMax(level)
    local rangeMax = 0
    local curScore = self:getLevelTotalScore(level)
    local nextScore = self:getLevelTotalScore(level + 1)
    if nextScore > 0 then
        rangeMax = curScore + math.floor((nextScore - curScore) / 2)
    else
        rangeMax = curScore
    end
    return rangeMax
end

-- 战令奖励领取成功
function TournArenaData:onReceivedBountyReward(successMap)
    for id, grade in pairs(successMap) do
        if self.bountyCollected[id] == nil then
            self.bountyCollected[id] = {}
        end
    
        if grade == GConst.TournArenaConst.BOUNTY_GRADE_TYPE.FREE then
            self.bountyCollected[id].normal = true
        elseif grade == GConst.TournArenaConst.BOUNTY_GRADE_TYPE.PAY1 then
            self.bountyCollected[id].superior = true
        elseif grade == GConst.TournArenaConst.BOUNTY_GRADE_TYPE.PAY2 then
            self.bountyCollected[id].superior_max = true
        end
    end

    self:setDirty()
end

-- 解锁战令等级成功
function TournArenaData:onBoughtBountyLevel()
    self.bountyLevel = self.bountyLevel + 1
    self:setDirty()
end

-- 排行榜--------------------------------------------------------------------------------------------------

-- 是否有排行榜红点
function TournArenaData:hasRankRedPoint()
    for rank, id in ipairs(self:getRankIdList()) do
        if self:isReachRankReward(rank) and not self:isReceivedRankReward(rank) then
            return true
        end
    end

    return false
end

-- <rank,id>
function TournArenaData:getRankIdList()
    if not self.rankIdList then
        self.rankIdList = GFunc.getTable(DataManager:getActivityRankByActId(self.actId) or {})
        table.sort(self.rankIdList, function(a, b)
            return a < b
        end)
    end
    return self.rankIdList
end

-- 获取排行榜的配置
function TournArenaData:getRankCfgByIndex(index)
    return ConfigManager:getConfig("activity_rank")[self:getRankIdList()[index]]
end

-- 活动总轮次数
function TournArenaData:getTotalTurnCount()
    local totalTime = self.endTime - self.startTime
    local day = totalTime / 86400

    return math.floor(day / GConst.TournWaveConst.PRESENT_TURN_DAY)
end

-- 获取当前排行榜阶段
function TournArenaData:getCurRankStep()
    return self.rankStep
end

-- 获取排名相应的奖励
function TournArenaData:getRewardByRank(rank)
    for index, id in ipairs(self:getRankIdList()) do
        local cfg = ConfigManager:getConfig("activity_rank")[id]
        if rank >= cfg.ranking[1] and rank <= cfg.ranking[2] then
            return cfg.reward
        end
    end
    return nil
end

-- 获取当前排行榜阶段剩余时间
function TournArenaData:getCurRankStepRemainTime()
    return self.rankStepEndTime - Time:getServerTime()
end

-- 获取排行榜数据
function TournArenaData:getRankListData(step)
    if self.ranks == nil then
        return nil
    end

    return self.ranks[step] and self.ranks[step].ranks or {}
end

-- 获取自己的排名
function TournArenaData:getSelfRank(step)
    if self.ranks == nil or self.ranks[step] == nil then
        return 0
    end

    return self.ranks[step].ownRank
end

-- 获取自己的积分
function TournArenaData:getSelfScore(step)
    if self.ranks == nil or self.ranks[step] == nil then
        return 0
    end

    return self.ranks[step].ownSorce
end

-- 是否满足段位奖励条件
function TournArenaData:isReachRankReward()
    if self:getCurRankStep() == 1 then
        return false
    end

    local lastRank
    if self:isFinalDay() then
        lastRank = self:getSelfRank(self:getTotalTurnCount())
    else
        lastRank = self:getSelfRank(self:getCurRankStep() - 1)
    end

    if lastRank and lastRank <= 0 then
        return false
    end
    return not self:isReceivedRankReward()
end

-- 是否已领取段位奖励
function TournArenaData:isReceivedRankReward()
    if self:getCurRankStep() == 1 then
        return false
    end

    local lastStep
    if self:isFinalDay() then
        lastStep = self:getTotalTurnCount()
    else
        lastStep = self:getCurRankStep() - 1
    end

    return self.rankCollected[lastStep] or false
end

-- 获取排行榜数据成功
function TournArenaData:onGetRankData(step, ranks, score, ownRank)
    if self.ranks == nil then
        self.ranks = {}
    end
    self.ranks[step] = {ownRank = ownRank, ownSorce = score, ranks = ranks}

    self:setDirty()
end

-- 领取排名奖励成功
function TournArenaData:onReceivedRankReward()
    local lastStep
    if self:isFinalDay() then
        lastStep = self:getTotalTurnCount()
    else
        lastStep = self:getCurRankStep() - 1
    end

    self.rankCollected[lastStep] = true

    self:setDirty()
end


-- 礼包---------------------------------------------------------------------------------------------------

-- 是否有礼包红点
function TournArenaData:hasGiftRedPoint()
    local ids = GConst.TournArenaConst.GIFT_IDS
    for index, id in pairs(ids) do
        if self:isFreeGift(id) and self:getGiftRemainTime(id) > 0 then
            return true
        end
    end

    return false
end

-- 获取礼包配置
function TournArenaData:getGiftCfg(giftId)
    return DataManager.ShopData:getActGiftConfig()[giftId]
end

-- 是否是免费礼包
function TournArenaData:isFreeGift(id)
    return DataManager.ShopData:getActGiftConfig()[id].recharge_id == nil
end

-- 获取礼包id列表
function TournArenaData:getGiftIdsSort()
    local result = {}
    local ids = GConst.TournArenaConst.GIFT_IDS
    for index, id in ipairs(ids) do
        local sort = id + 10000000000

        if self:isFreeGift(id) then
            sort = sort - 10000000
        end

        if self:getGiftRemainTime(id) > 0 then
            sort = sort - 10000
        end
        table.insert(result, {id = id, sort = sort})
    end

    table.sort(result, function (a, b)
        return a.sort < b.sort
    end)

    return result
end

-- 礼包剩余购买次数
function TournArenaData:getGiftRemainTime(giftId)
    if self:isFreeGift(giftId) then
        local giftData = DataManager.ShopData:getActGiftDetailData(PayManager.PURCHARSE_TYPE.ACT_GIFT, giftId)
        if giftData and giftData.buy_count > 0 and giftData.latest_buy_at then
            if Time:getBeginningOfOneDay(Time:getServerTime()) == Time:getBeginningOfOneDay(giftData.latest_buy_at // 1000) then
                return 0
            end
        end
        return 1
    else
        return DataManager.ShopData:getGiftRemainBuyNum(giftId) or 0
    end
end

return TournArenaData