local ACT_ID = 306
local PRO_ACT_ID = 220102
local UTRAL_ACT_ID = 220202
local ActPvpData = class("ActPvpData", BaseData)

ActPvpData.BOUNTY_TYPE = {
    NORMAL = "normal",
    SUPERIOR = "superior",
    SUPERIOR_MAX = "superior_max"
}

ActPvpData.BOUNTY_TYPE_TO_NUM = {
    [ActPvpData.BOUNTY_TYPE.NORMAL] = 0,
    [ActPvpData.BOUNTY_TYPE.SUPERIOR] = 1,
    [ActPvpData.BOUNTY_TYPE.SUPERIOR_MAX] = 2
}

function ActPvpData:ctor()
    self.endTime = 0
    self.startTime = 0
    self.data.isDirty = false

    self.playing = false
    self.enterCountDaily = 0
    self.totalFightCount = 0
    self.totalWinCount = 0
    self.todayWinCount = 0
    self.winCount = 0
    self.loseCount = 0
    self.heroeAndSkins = {}
    self.currentSelectPairId = {}
    self.nextSelectFourId = {}
    self.flushCount = 0
    self.matchCdEndAt = 0
    self.todayAdCount = 0
    self.rivalInfo = {}
    self.dailyRewards = {}
    self.gotRankRewards = false
    self.exp = 0
    self.level = 1
    self.collected = {}
end

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

function ActPvpData:setActivityId(actId)
    self.activity_id = actId
end

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

function ActPvpData:clear()
    DataManager:unregisterCrossDayFunc("ActPvpData")
end

function ActPvpData:init(data)
    if not data.enter_count_daily then -- 没数据
        self:setNeedUpdate(false)
    else
        self:updateData(data)
    end
    self:getBountyList()
    DataManager:registerCrossDayFunc("ActPvpData", function()
        if self:isFinalDay() then
            self.playing = false
        end
        self.todayWinCount = 0
        self.enterCountDaily = 0
        self.todayAdCount = 0
        self.dailyRewards = {}
        self:setDirty()
    end)
end

function ActPvpData:updateData(data)
    if not data then
        return
    end
    self:setNeedUpdate(false)
    self.playing = data.playing
    self.enterCountDaily = data.enter_count_daily
    self.totalWinCount = data.total_win_count
    self.todayWinCount = data.daily_win_count
    self.winCount = data.win_count
    self.loseCount = data.lose_count
    self.todayAdCount = data.today_ad_count
    self.dailyRewards = data.daily_rewards
    self.gotRankRewards = data.rank_rewards
    self.exp = data.exp
    self.level = data.level
    self.collected = data.collected
    self:updateRivalInfo(data.rival_info, data.match_cd_end_at)
    self:updateHerosInfo(data.heroes, data.current_select_pair_id, data.next_select_four_id)
    self.flushCount = data.flush_count

    if self:isFinalDay() then
        self.playing = false
    end

    self:setDirty()
end

function ActPvpData: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 ActPvpData:getIsOpen()
    if GFunc.isShenhe() or not self.endTime 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天的号，看不到
        self.isOpen = false
        return false
    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.ShopData:resetGiftBoughtNum(PayManager.PURCHARSE_TYPE.ACT_GIFT, PRO_ACT_ID)
        DataManager.ShopData:resetGiftBoughtNum(PayManager.PURCHARSE_TYPE.ACT_GIFT, UTRAL_ACT_ID)
    end
    self.isOpen = isOpen
    return isOpen
end

function ActPvpData:getRemainTime()
    return self.endTime - Time:getServerTime()
end

function ActPvpData:isFinalDay()
    return self:getRemainTime() <= 86400
end

function ActPvpData:isPlaying()
    return self.playing
end

function ActPvpData:getEnterCount()
    return self.enterCountDaily
end

function ActPvpData:getFreeEnterLimit()
    if not self.freeEnterLimit then
        self.freeEnterLimit = GFunc.getConstIntValue("activity_pvp_time")
    end
    return self.freeEnterLimit
end

function ActPvpData:getFreeEnterCount()
    return self:getFreeEnterLimit() - self:getEnterCount()
end

function ActPvpData:getEnterCost()
    if not self.enterBaseCost then
        self.enterBaseCost = GFunc.getConstReward("activity_pvp_cost")
    end
    if not self.enterAddCost then
        self.enterAddCost = GFunc.getConstReward("activity_pvp_costadd")
    end
    if not self.enterCost then
        self.enterCost = GFunc.getTable(self.enterBaseCost)
    end
    local count = self:getFreeEnterCount()
    if count > 0 then
        self.enterCost.num = 0
    else
        count = 0 - count
        self.enterCost.num = self.enterBaseCost.num + self.enterAddCost.num * count
    end
    return self.enterCost
end

function ActPvpData:getWinCount()
    return self.winCount or 0
end

function ActPvpData:getWinLimit()
    if not self.winLimit then
        self.winLimit = GFunc.getConstIntValue("activity_pvp_win_times")
    end
    return self.winLimit
end

function ActPvpData:getLoseCount()
    return self.loseCount or 0
end

function ActPvpData:getLoseLimit()
    if not self.loseLimit then
        self.loseLimit = GFunc.getConstIntValue("activity_pvp_lose_times")
    end
    return self.loseLimit
end

function ActPvpData:updateHerosInfo(heroes, pairIds, nextSelectFourId)
    if heroes then
        self.heroEntities = {}
        for heroId, skinId in pairs(heroes) do
            if DataManager.HeroData:isExistHeroById(heroId) then
                local level = self:getHeroLv()
                local heroEntity = DataManager.HeroData:getEntity({id = heroId, level = level, skin = skinId})
                heroEntity:setSkins({skinId})
                self.heroEntities[heroEntity:getMatchType()] = heroEntity
            end
        end
    end

    self:updateSelectInfo(pairIds, nextSelectFourId)
end

function ActPvpData:updateSelectInfo(pairIds, nextSelectFourId)
    self.currentSelectPairId = pairIds
    self.nextSelectFourId = nextSelectFourId
    self:setDirty()
end

function ActPvpData:getHeros()
    return self.heroEntities or {}
end

function ActPvpData:getCurSelectPairId()
    return self.currentSelectPairId
end

function ActPvpData:getNextSelectFourId()
    return self.nextSelectFourId
end

function ActPvpData:getSelectHeroId(selectId)
    local cfg = ConfigManager:getConfig("activity_pvp")[selectId]
    if not cfg then
        return
    end
    return cfg.hero_id
end

function ActPvpData:getRematchConstGem()
    return GFunc.getConstIntValue("arena_refresh_cost")
end

function ActPvpData:updateRivalInfo(rivalInfo, endCd)
    self.rivalInfo = rivalInfo or {}
    self.matchCdEndAt = GFunc.formatTimeStep(endCd)
    if self.rivalInfo.rival_heroes then
        self.rivalHeroEntities = {}
        for heroId, skinId in pairs(self.rivalInfo.rival_heroes) do
            if DataManager.HeroData:isExistHeroById(heroId) then
                local level = self:getHeroLv()
                local heroEntity = DataManager.HeroData:getEntity({id = heroId, level = level, skin = skinId})
                heroEntity:setSkins({skinId})
                self.rivalHeroEntities[heroEntity:getMatchType()] = heroEntity
            end
        end
    end
end

function ActPvpData:getRivalInfo()
    return self.rivalInfo
end
function ActPvpData:getRivalInfoHeroes()
    return self.rivalHeroEntities
end

function ActPvpData:getMatchCdEndAt()
    return self.matchCdEndAt
end

function ActPvpData:setMatchCdEndAt(isAd)
    self.matchCdEndAt = Time:getServerTime()
    if isAd then
        self.todayAdCount = self.todayAdCount +1
    end
end

function ActPvpData:getMatchCdEndTime()
    return self.matchCdEndAt - Time:getServerTime()
end

function ActPvpData:getCanAdRefreshHero()
    return self.todayAdCount <= 0
end

function ActPvpData:getNeedReMatch()
    if not self.rivalInfo or not self.rivalInfo.level then
        return true
    end

    return false
end

function ActPvpData:canGetDailyReward(winCount)
    if self.todayWinCount >= winCount then
        if not self:gotDailyReward(winCount) then
            return true
        end
    end

    return false
end

function ActPvpData:winCountEnough(winCount)
    return self.todayWinCount >= winCount
end

function ActPvpData:gotDailyReward(winCount)
    local index = self:getWinCountMap()[winCount]
    if not index then
        return false
    end
    for _, gotId in ipairs(self.dailyRewards) do
        if gotId == index then
            return true
        end
    end

    return false
end

function ActPvpData:setDailyReward(id)
    table.insert(self.dailyRewards, id)
    self:setDirty()
end

function ActPvpData:getDailyRewards(winCount)
    local cfg = ConfigManager:getConfig("activity_pvp_wingift")
    for index, info in ipairs(cfg) do
        if info.win == winCount then
            return info.reward
        end
    end
end

function ActPvpData:getWinCountMap()
    if not self.winCountMap then
        self.winCountMap = {}
        local cfg = ConfigManager:getConfig("activity_pvp_wingift")
        for index, info in ipairs(cfg) do
            self.winCountMap[info.win] = index
        end
    end

    return self.winCountMap
end

function ActPvpData:getTotalFightCount()
    return self.totalFightCount
end

function ActPvpData:getTotalWinCount()
    return self.totalWinCount
end

function ActPvpData:getNeedUpdateData()
    return self.needUpdateData
end

function ActPvpData:setNeedUpdate(need)
    self.needUpdateData = need
end

function ActPvpData:getHeroLv()
    local maxlv = ConfigManager:getConfigNum("hero_level")
    return math.min(6 + self.winCount, maxlv)
end

function ActPvpData:getRp()
    if self:canGetRankReward() then
        return true
    end
    if self:getBountyRp() then
        return true
    end
    return false
end

function ActPvpData:addFlushCount()
    self.flushCount = self.flushCount + 1
end

function ActPvpData:getFlushCount()
    return self.flushCount or 0
end

function ActPvpData:getCanAdFlush()
    return self.flushCount < self:getAdFlushLimit()
end

function ActPvpData:getAdFlushLimit()
    if not self.adFlushLimit then
        self.adFlushLimit = GFunc.getConstIntValue("activity_pvp_refresh_ad_times")
    end
    return self.adFlushLimit
end

function ActPvpData:getFlushCost()
    if not self.flushCost then
        self.flushCost = GFunc.getConstReward("activity_pvp_refresh_cost")
    end
    return self.flushCost
end

function ActPvpData:getLastTurnWin()
    return self.lastTurnWin
end

function ActPvpData:setLastTurnWin(win)
    self.lastTurnWin = win
end

function ActPvpData:getHeroLevelUp()
    return self.heroLevelUp
end

function ActPvpData:setHeroLevelUp(up)
    self.heroLevelUp = up
end

function ActPvpData:recordLastBountyLevel()
    self.lastBountyLevel = self.level
    self.lastBountyExp = self.exp
end

function ActPvpData:getLastBountyLevel()
    return self.lastBountyLevel, self.lastBountyExp
end

---- 排行榜

function ActPvpData:updateRankInfo(ranks, selfRank)
    self.rankList = ranks
    self.selfRank = selfRank
    self.lastUpdateRankTs = Time:getServerTime()
    self:setDirty()
end

function ActPvpData:getRankList()
    return self.rankList or {}
end

function ActPvpData:getSelfRank()
    return self.selfRank or 0
end

function ActPvpData:getNeedUpdateRank()
    if not self.lastUpdateRankTs then
        return true
    end

    return (Time:getServerTime() - self.lastUpdateRankTs) > 10 -- 10秒拉一次
end

function ActPvpData:canGetRankReward()
    if not self:isFinalDay() then
        return false
    end
    if self.selfRank and self.selfRank <= 0 then
        return false
    end
    return not self.gotRankRewards
end

function ActPvpData:getGotRankReward()
    return self.gotRankRewards
end

function ActPvpData:setGotRankReward()
    self.gotRankRewards = true
    self:setDirty()
end

function ActPvpData:getRankConfig()
    return ConfigManager:getConfig("activity_rank")
end

function ActPvpData:getRankRewardList()
    if not self.rankRewardList then
        self.rankRewardList = GFunc.getTable(DataManager:getActivityRankByActId(self.activity_id or ACT_ID) or {})
        table.sort(self.rankRewardList, function(a, b)
            return a < b
        end)
    end
    return self.rankRewardList
end


function ActPvpData: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 list = self:getRankRewardList()
        for index, id in ipairs(list) 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 ActPvpData:getBountyExp()
    return self.exp
end

function ActPvpData:getBountyLevel()
    return self.level
end

function ActPvpData:setBountyLevel(level)
    if level > self.minBountyBaseLv then
        level = level - self.minBountyBaseLv
    end
    self.level = level
    self:setDirty()
end

function ActPvpData:getMaxBountyLevel()
    self:getBountyList()
    return self.maxBountyLv
end

function ActPvpData:getBountyCfg()
    return ConfigManager:getConfig("activity_bounty_level")
end

function ActPvpData:getBountyLevelExp(level)
    local id = self:getBountyList()[level]
    if not id then
        return 0
    end
    local info = self:getBountyCfg()[id]
    if not info then
        return 0
    end
    return info.exp or 0
end

function ActPvpData: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)
        self.maxBountyLv = #self.bountyList
        self.minBountyBaseLv = (self.bountyList[1] or 1)
        self.minBountyBaseLv = self.minBountyBaseLv - 1
    end
    return self.bountyList
end

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

function ActPvpData:getBountyCollected(id, fundType)
    if not self.collected[id] then
        return false
    end
    return self.collected[id][fundType]
end

function ActPvpData:getBountyReward(id, fundType)
    local info = self:getBountyCfg()[id]
    if not info then
        return
    end

    if fundType == ActPvpData.BOUNTY_TYPE.NORMAL then
        return info.reward
    elseif fundType == ActPvpData.BOUNTY_TYPE.SUPERIOR then
        return info.reward_pro
    elseif fundType == ActPvpData.BOUNTY_TYPE.SUPERIOR_MAX then
        return info.reward_pro_max
    end
end

function ActPvpData:setBountyCollected(idGrades)
    if not idGrades then
        return
    end
    for id, grade in pairs(idGrades) do
        if not self.collected[id] then
            self.collected[id] = {}
        end
        if grade == 0 then
            self.collected[id][ActPvpData.BOUNTY_TYPE.NORMAL] = true
        elseif grade == 1 then
            self.collected[id][ActPvpData.BOUNTY_TYPE.SUPERIOR] = true
        elseif grade == 2 then
            self.collected[id][ActPvpData.BOUNTY_TYPE.SUPERIOR_MAX] = true
        end
    end

    self:setDirty()
end

function ActPvpData:getBountyCanGet(level, bountyType)
    if self:getBountyCollected(level, bountyType) then
        return false
    end

    if bountyType == ActPvpData.BOUNTY_TYPE.SUPERIOR then
        if not self:getProBought() then
            return false
        end
    elseif bountyType == ActPvpData.BOUNTY_TYPE.SUPERIOR_MAX then
        if not self:getUtralBought() then
            return false
        end
    end

    return self.level + self.minBountyBaseLv >= level
end

function ActPvpData:getBountyLevelEnough(level)
    return self.level + self.minBountyBaseLv >= level
end

function ActPvpData:getBountyLevelId(level)
    return level + self.minBountyBaseLv
end

function ActPvpData:getProActId()
    return PRO_ACT_ID
end

function ActPvpData: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 ActPvpData:getProBought()
    if not self.proBounght then
        if DataManager.ShopData:getGiftBoughtNum(PayManager.PURCHARSE_TYPE.ACT_GIFT, PRO_ACT_ID) > 0 then
            self.proBounght = true
        end
    end

    return self.proBounght
end

function ActPvpData:getUtralActId()
    return UTRAL_ACT_ID
end

function ActPvpData: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 ActPvpData:getUtralBought()
    if not self.utralBounght then
        if DataManager.ShopData:getGiftBoughtNum(PayManager.PURCHARSE_TYPE.ACT_GIFT, UTRAL_ACT_ID) > 0 then
            self.utralBounght = true
        end
    end
    return self.utralBounght
end

function ActPvpData:getBountyRp()
    self:getBountyList()
    for level = self.minBountyBaseLv + 1, self.level + self.minBountyBaseLv do
        for k, bountyType in pairs(ActPvpData.BOUNTY_TYPE) do
            if self:getBountyCanGet(level, bountyType) then
                return true
            end
        end
    end

    return false
end

function ActPvpData:getActPvpShowHelpTag()
    if self.showHelpTag == nil then
        self.showHelpTag = LocalData:getActPvpShowHelpTag(self.activity_id or ACT_ID) == 1
    end
    return self.showHelpTag
end

function ActPvpData:recordActPvpShowHelpTag()
    if self.showHelpTag then
        return
    end

    self.showHelpTag = true
    LocalData:recordActPvpShowHelpTag(self.activity_id or ACT_ID)
end

return ActPvpData