local DungeonData = class("DungeonData", BaseData)

local SORT_ORDER = {
    [ModuleManager.MODULE_KEY.DUNGEON_GOLD] = 1,
    [ModuleManager.MODULE_KEY.DUNGEON_SHARDS] = 2,
    [ModuleManager.MODULE_KEY.DUNGEON_WEAPON] = 3,
    [ModuleManager.MODULE_KEY.DUNGEON_ARMOR] = 4,
    [ModuleManager.MODULE_KEY.RUNES_OPEN] = 5,
}

-- 所有活动副本数据

function DungeonData:ctor()
    self.data.isDirty = false
end

function DungeonData:clear()
    if self.dataDungeons then
        for _, entity in pairs(self.dataDungeons) do
            entity:clear()
        end
    end
end

-- 初始化金币副本数据
function DungeonData:initDungeonGold(data)
    if data == nil then
        return
    end

    if EDITOR_MODE then
        Logger.logHighlight("更新金币副本数据")
        Logger.printTable(data)
    end

    self:initAllDataClass()
    self.dataDungeons[ModuleManager.MODULE_KEY.DUNGEON_GOLD]:init(data)
    self.data.gold = data
    self:setDirty()
end

-- 初始化碎片副本数据
function DungeonData:initDungeonShards(data)
    if data == nil then
        return
    end

    if EDITOR_MODE then
        Logger.logHighlight("更新碎片副本数据")
        Logger.printTable(data)
    end

    self:initAllDataClass()
    self.dataDungeons[ModuleManager.MODULE_KEY.DUNGEON_SHARDS]:init(data)
    self.data.shards = data
    self:setDirty()
end

-- 初始化支线副本数据
function DungeonData:initDungeonArmor(data)
    if data == nil then
        return
    end

    if EDITOR_MODE then
        Logger.logHighlight("更新支线副本数据")
        Logger.printTable(data)
    end

    self:initAllDataClass()
    self.dataDungeons[ModuleManager.MODULE_KEY.DUNGEON_ARMOR]:init(data)
    self.data.armor = data
    self:setDirty()
end

-- 初始化支线副本数据
function DungeonData:initDungeonWeapon(data)
    if data == nil then
        return
    end

    if EDITOR_MODE then
        Logger.logHighlight("更新武器副本数据")
        Logger.printTable(data)
    end

    self:initAllDataClass()
    self.dataDungeons[ModuleManager.MODULE_KEY.DUNGEON_WEAPON]:init(data)
    self.data.weapon = data
    self:setDirty()
end

-- 初始化符文副本数据
function DungeonData:initDungeonRune(data)
    if data == nil then
        return
    end

    self:initAllDataClass()
    self.dataDungeons[ModuleManager.MODULE_KEY.RUNES_OPEN]:init(data)
    self.data.rune = data
    self:setDirty()
end


-- 初始化所有副本数据类
function DungeonData:initAllDataClass()
    if self.dataDungeons == nil then
        self.dataDungeons = {}
        self.dataDungeons[ModuleManager.MODULE_KEY.DUNGEON_GOLD] = require "app/userdata/dungeon/dungeon_gold_entity":create()
        self.dataDungeons[ModuleManager.MODULE_KEY.DUNGEON_SHARDS] = require "app/userdata/dungeon/dungeon_shards_entity":create()
        self.dataDungeons[ModuleManager.MODULE_KEY.DUNGEON_ARMOR] = require "app/userdata/dungeon/dungeon_armor_entity":create()
        self.dataDungeons[ModuleManager.MODULE_KEY.DUNGEON_WEAPON] = require "app/userdata/dungeon/dungeon_weapon_entity":create()
        self.dataDungeons[ModuleManager.MODULE_KEY.RUNES_OPEN] = require "app/userdata/dungeon/dungeon_rune_entity":create()

        if EDITOR_MODE then
            Logger.logHighlight("星期".. tostring(Time:getWeekByTimeStamp()))
        end
    end

    self.initDay = Time:getBeginningOfServerToday()
end

function DungeonData:getIfCanReset()
	return self.initDay < Time:getBeginningOfServerToday()
end

-- 跨天处理
function DungeonData:onDayChange()
    self.data.gold.today_challenge_count = 0
    self.data.shards.today_challenge_count = 0

    if EDITOR_MODE then
        Logger.logHighlight("星期".. tostring(Time:getWeekByTimeStamp()))
    end

    self:initDungeonGold(self.data.gold)
    self:initDungeonShards(self.data.shards)
    EventManager:dispatchEvent(EventManager.CUSTOM_EVENT.DUNGEON_DAY_CHANGE)
end

-- 客户端处理副本次数+1的情况
function DungeonData:onFightCountReduce(moduleKey)
    if moduleKey == ModuleManager.MODULE_KEY.DUNGEON_GOLD then
        self.data.gold.today_challenge_count = self.data.gold.today_challenge_count + 1
        self:initDungeonGold(self.data.gold)
    elseif moduleKey == ModuleManager.MODULE_KEY.DUNGEON_SHARDS then
        self.data.shards.today_challenge_count = self.data.shards.today_challenge_count + 1
        self:initDungeonShards(self.data.shards)
    end
end

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

-- 是否开启任意一个副本
function DungeonData:isOpenAnyone()
    for key, value in pairs(self.dataDungeons) do
        if self:isOpen(key) then
            return true
        end
    end
    return false
end

-- 某副本是否已开启
function DungeonData:isOpen(moduleKey)
    if not ModuleManager:getIsOpen(moduleKey, true) then
        return false
    end
    return true
end

-- 返回已开启的副本
function DungeonData:getOpenDungeons()
    if self.dungeonStage == nil then
        self.dungeonStage = {}
        for module, entity in pairs(self.dataDungeons) do
            local openStage = ConfigManager:getConfig("func_open")[module].stage
            self.dungeonStage[module] = openStage
        end
        table.sort(self.dungeonStage, function(a, b)
            return a < b
        end)
    end

    local openDungeons = {}
    -- 开启且活跃
    table.foreach(self.dungeonStage, function(module, s)
        if self:isOpen(module) and self:isActive(module) then
            local count = self:getRemainTimes(module)
            if count > 0 then
                count = 100
            else
                count = 200
            end
            table.insert(openDungeons, {
                sort = SORT_ORDER[module] + 1000 + count, -- 系数 + 开启1000 + 剩余次数
                module = module
            })
        end
    end)
    -- 开启且不活跃
    if not GFunc.isShenhe() then
        table.foreach(self.dungeonStage, function(module, s)
            if self:isOpen(module) and not self:isActive(module) then
                table.insert(openDungeons, {
                    sort = SORT_ORDER[module] + 2000, -- 系数 + 未开启2000
                    module = module
                })
            end
        end)
    end

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

    if EDITOR_MODE then
        Logger.logHighlight("已开启副本:")
        Logger.printTable(openDungeons)
    end
    return openDungeons
end

-- 是否在活动副本时间内
function DungeonData:isActive(moduleKey)
    if not self:isOpen(moduleKey) then
        return false
    end

    -- 判断周期
    if self:isActiveCycle(moduleKey, Time:getWeekByTimeStamp()) then
        return true
    else
        return false
    end
end

-- 判断是否在活跃周期内
function DungeonData:isActiveCycle(moduleKey, checkWeek)
    if not self.dataDungeons[moduleKey] then
        return false
    end

    if self:getIsAllTimeOpen(moduleKey) then
        return true
    end

    local closeTime = self.dataDungeons[moduleKey]:getCloseTime()
    if closeTime and closeTime > 0 then
        return true
    end

    for index, week in ipairs(self.dataDungeons[moduleKey]:getOpenWeekCycle()) do
        if week == checkWeek then
            return true
        end
    end
    return false
end

-- 是否任意一个副本可以挑战
function DungeonData:isCanChallengeAnyone()
    for key, value in pairs(self.dataDungeons) do
        if self:isCanChallenge(key) then
            return true
        end
    end
    return false
end

-- 副本是否可以挑战
function DungeonData:isCanChallenge(moduleKey)
    if not self:isActive(moduleKey) then
        return false
    end
    if not (self:getRemainTimes(moduleKey) > 0) then
        return false
    end
    if not self:isEnoughHp(moduleKey) then
        return false
    end
    return true
end

-- 副本是否可以扫荡
function DungeonData:isCanSweep(moduleKey, id)
    if not self:isActive(moduleKey) then
        return false
    end
    if not (self:getRemainTimes(moduleKey) > 0) then
        return false
    end
    if not self:isEnoughHp(moduleKey) then
        return false
    end
    if not self:getPassedMaxId(moduleKey) >= id then
        return false
    end
    return true
end

-- 获取副本挑战总次数
function DungeonData:getTotalCount(moduleKey)
    return self.dataDungeons[moduleKey]:getTotalChallengeCount()
end

-- 获取副本今日剩余次数
function DungeonData:getRemainTimes(moduleKey)
    if not self:isActive(moduleKey) then
        return 0
    end
    if not self.dataDungeons[moduleKey] then
        return 0
    end

    return self.dataDungeons[moduleKey]:getTodayRemainLimitCount()
end

-- 体力是否足够
function DungeonData:isEnoughHp(moduleKey)
    local const = self:getChallengeHpCost(moduleKey)
    local constNum = 0
    if const then
        constNum =  GFunc.getRewardNum(const)
    end
    return constNum <= DataManager.BagData.ItemData:getVit()
end

-- 获取挑战体力消耗
function DungeonData:getChallengeHpCost(moduleKey)
    if not self:isActive(moduleKey) then
        return 0
    end
    if not self.dataDungeons[moduleKey] then
        return 0
    end

    return self.dataDungeons[moduleKey]:getChallengeHpCost()
end

-- 获取副本下个状态改变时间
function DungeonData:geNextTime(moduleKey)
    if self:isActive(moduleKey) then
        return self:getCloseTime(moduleKey)
    else
        return self:getOpenTime(moduleKey)
    end
end

-- 获取副本开启倒计时
function DungeonData:getOpenTime(moduleKey)
    if not self.dataDungeons[moduleKey] then
        return 0
    end

    local isClose = true
    local count = 0
    while isClose do
        local checkWeek = Time:getWeekByTimeStamp(Time:getServerTime() + ((count + 1) * 86400))
        if self:isActiveCycle(moduleKey, checkWeek) then
            isClose = false
        else
            count = count + 1
        end
    end

    return Time:getTodaySurplusTime() + (count * 86400)
end

-- 获取副本关闭倒计时
function DungeonData:getCloseTime(moduleKey)
    if not self.dataDungeons[moduleKey] then
        return 0
    end

    if self:getIsAllTimeOpen(moduleKey) then
        return 1
    end

    if self.dataDungeons[moduleKey]:getCloseTime() then
        return self.dataDungeons[moduleKey]:getCloseTime()
    end

    local isActive = true
    local count = 0
    while isActive do
        local checkWeek = Time:getWeekByTimeStamp(Time:getServerTime() + ((count + 1) * 86400))
        if not self:isActiveCycle(moduleKey, checkWeek) then
            isActive = false
        else
            count = count + 1
        end
    end

    return Time:getTodaySurplusTime() + (count * 86400)
end

-- 获取看板展示的副本奖励（返回item id list）
function DungeonData:getBoardShowRewardId(moduleKey)
	return self.dataDungeons[moduleKey]:getBoardShowRewardId()
end

-- 获取展示副本首通奖励个数
function DungeonData:getFirstRewardNum(moduleKey, id)
    -- 通关后，不展示首通奖励
    return self.dataDungeons[moduleKey]:getFirstRewardNum(id)
end

-- 获取展示副本通关奖励个数
function DungeonData:getPassRewardNum(moduleKey, id)
    return self.dataDungeons[moduleKey]:getPassRewardNum(id)
end

--获取副本已解锁最大id
function DungeonData:getUnlockMaxId(moduleKey)
    local id = self.dataDungeons[moduleKey]:getPassedMaxId() + 1
    if id > self:getConfigMaxId(moduleKey) then
        id = id - 1
    end
    return id
end

-- 获取副本配置的最高关卡
function DungeonData:getConfigMaxId(moduleKey)
    return #self.dataDungeons[moduleKey]:getConfig()
end

--获取副本已通关的最高关卡id
function DungeonData:getPassedMaxId(moduleKey)
    return self.dataDungeons[moduleKey]:getPassedMaxId()
end

-- 获取副本标题文案
function DungeonData:getTitle(moduleKey)
    return self.dataDungeons[moduleKey]:getTitleString()
end 

-- 获取副本规则描述
function DungeonData:getRule(moduleKey)
    return self.dataDungeons[moduleKey]:getRuleString()
end

-- 获取副本当前关卡buff
function DungeonData:getBossBuff(moduleKey, id)
    return self.dataDungeons[moduleKey]:getBossBuff(id)
end

-- 获取副本开启时间描述
function DungeonData:getOpenTimeDesc(moduleKey)
    return self.dataDungeons[moduleKey]:getOpenWeekString()
end

-- 获取副本角标图
function DungeonData:getIcon(moduleKey)
    return self.dataDungeons[moduleKey]:getIcon()
end

-- 获取副本banner图
function DungeonData:getBanner(moduleKey)
    return self.dataDungeons[moduleKey]:getBanner()
end

-- 获取开启时间文本颜色
function DungeonData:getOpenTextColor(moduleKey)
    return self.dataDungeons[moduleKey]:getOpenTextColor()
end

function DungeonData:setCurFightChapterId(chapterId)
    self.curFightchapterId = chapterId or 1
end

function DungeonData:getCurFightChapterId()
    return self.curFightchapterId or 1
end

function DungeonData:getIsAllTimeOpen(moduleKey)
    return self.dataDungeons[moduleKey]:getIsAllTimeOpen()
end

function DungeonData:isNoTotalLimit(moduleKey)
    return self.dataDungeons[moduleKey]:isNoTotalLimit()
end

function DungeonData:isNotShowLimitCount(moduleKey)
    return self.dataDungeons[moduleKey]:isNotShowLimitCount()
end

function DungeonData:onClickFight(moduleKey)
    self.dataDungeons[moduleKey]:onClickFight()
end

function DungeonData:getDungeonDataByType(moduleKey)
    return self.dataDungeons[moduleKey]
end

function DungeonData:getDungeonBIStr()
	local str
    if not self.dataDungeons then
        return GConst.EMPTY_STRING
    end
	for moduleKey, entity in pairs(self.dataDungeons) do
        if str then
            str = str .. "|"
        else
            str = GConst.EMPTY_STRING
        end
        str = str .. string.gsub(moduleKey, "_open", "") .. ":" .. entity:getPassedMaxId()
	end
	return str
end

return DungeonData