local this = {}
local dungeonGroupTpl = L_GameTpl:getDungeonGroupTpl()
local _kiBoDuelTpl = L_GameTpl:getKiboDuelTpl()
local _gameConstTpl = L_GameTpl:getGameConstTpl()
local _kiboDuelChapterTpl = L_GameTpl:getKiBoDuelChapterTpl()
local _kiboDuelGroupTpl = L_GameTpl:getKiBoDuelGroupTpl()
local _trialPetTpl = L_GameTpl:getTrialPetTpl()
local petTpl = L_GameTpl:getPetTpl()

function this:init()
  this.super.init(self)
  self.data = {
    curLevelIds = {},
    curRealUseFormationSlot = 1,
    curUseFormationSlot = 1,
    petDuelFormationGroupInfo = {},
    petDuelRecordInfo = {},
    curChallengeLevelId = 1001,
    curChallengeGroupId = 1001,
    lastChapterModeLevelId = nil,
    trialPetGuids = {},
    petExpInfo = {},
    curHeroGuid = 0
  }
end

function this:getNPCLevelIds()
  if self.data.curLevelIds[self.data.curChallengeGroupId] then
    return self.data.curLevelIds[self.data.curChallengeGroupId]
  end
  self.data.curLevelIds[self.data.curChallengeGroupId] = {}
  for _, v in pairs(dungeonGroupTpl:getValue()) do
    if v.groupId == self.data.curChallengeGroupId then
      table.insert(self.data.curLevelIds[self.data.curChallengeGroupId], v.id)
    end
  end
  table.sort(self.data.curLevelIds[self.data.curChallengeGroupId], function(a, b)
    local TplA = dungeonGroupTpl:getTplById(a)
    local TplB = dungeonGroupTpl:getTplById(b)
    return dungeonGroupTpl:getDungeonGroupOrder(TplA) < dungeonGroupTpl:getDungeonGroupOrder(TplB)
  end)
  return self.data.curLevelIds[self.data.curChallengeGroupId]
end

function this:checkLevelUnlocked(levelId)
  local levelIds = self:getNPCLevelIds()
  for i = #levelIds, 1, -1 do
    if L_PetDuelStore:getIsSuccess(levelIds[i]) and (levelId == levelIds[i] or levelId == levelIds[i] + 1) then
      return true
    end
  end
  return levelIds[1] == levelId
end

function this:getDefaultSelectLevelId()
  local levelIds = self:getNPCLevelIds()
  for i = #levelIds, 1, -1 do
    if self:checkLevelUnlocked(levelIds[i]) then
      return levelIds[i]
    end
  end
  return levelIds[1]
end

function this:getPetDuelHeroSkills()
  local curLevelId = self:getCurChallengeLevelId()
  if not self.data.petDuelHeroSkillInfo[curLevelId] then
    return {}
  end
  return self.data.petDuelHeroSkillInfo[curLevelId].hero_skills or {}
end

function this:getCurPetDuelFormationSlot()
  if _kiBoDuelTpl:isKiboLock(self:getCurChallengeLevelId()) then
    return L_Const.kiBoDuelBlockSlot
  end
  return self.data.curUseFormationSlot
end

function this:setCurPetDuelFormationSlot(slotId)
  if _kiBoDuelTpl:isKiboLock(self:getCurChallengeLevelId()) then
    return
  end
  if slotId < 1 then
    slotId = 1
  end
  self.data.curUseFormationSlot = slotId
end

function this:getCurRealPetDuelFormationSlot()
  if _kiBoDuelTpl:isKiboLock(self:getCurChallengeLevelId()) then
    return L_Const.kiBoDuelBlockSlot
  end
  return self.data.curRealUseFormationSlot
end

function this:setCurRealPetDuelFormationSlot(slotId)
  if _kiBoDuelTpl:isKiboLock(self:getCurChallengeLevelId()) then
    return
  end
  self.data.curRealUseFormationSlot = slotId
end

function this:getPetDuelFormationGroupInfo(slotId)
  return self.data.petDuelFormationGroupInfo[slotId] or {}
end

function this:getPetDuelFormationPetGuids(slotId)
  local groupInfo = self:getPetDuelFormationGroupInfo(slotId)
  if groupInfo.pet_guids and #groupInfo.pet_guids > 0 then
    return groupInfo.pet_guids
  end
  local pet_guids = {}
  for i = 1, 8 do
    table.insert(pet_guids, {is_trial = false, id = 0})
  end
  return pet_guids
end

function this:getPetDuelFormationHeroGuid(slotId)
  local duelId = self:getCurChallengeLevelId()
  if L_KiBoDuelManager:isTrialDuel(duelId) then
    return self.data.curHeroGuid
  end
  local groupInfo = self:getPetDuelFormationGroupInfo(slotId)
  return groupInfo.hero or 0
end

function this:getPetDuelFormationHeroSkills(slotId)
  local groupInfo = self:getPetDuelFormationGroupInfo(slotId)
  return groupInfo.hero_skills or {}
end

function this:getCurChallengeLevelId()
  return self.data.curChallengeLevelId
end

function this:setCurChallengeLevelId(levelId)
  self.data.curChallengeLevelId = levelId
end

function this:getChapterChallengeSuccessSaveKey(chapterId)
  return string.format("%s_%s_%s", L_PlayerStore:getPlayerId(), "pageDuelChapterPass", chapterId)
end

function this:getModeChallengeSuccessSaveKey(modeId)
  return string.format("%s_%s_%s", L_PlayerStore:getPlayerId(), "pageDuelModeUnlock", modeId)
end

function this:getLastLevelIdSaveKey(modeId)
  if not modeId then
    return string.format("%s_%s", L_PlayerStore:getPlayerId(), "pageDuelLastChallengeLevelId")
  end
  return string.format("%s_%s_%s", L_PlayerStore:getPlayerId(), "pageDuelLastChallengeLevelId", modeId)
end

function this:getLastChapterModeLevelId()
  if not self.data.lastChapterModeLevelId then
    local modeInfo = _kiboDuelChapterTpl:getModeInfo(1)
    local chapterCfg = modeInfo[1]
    local chapterInfo = _kiboDuelGroupTpl:getChapterLevelInfo(_kiboDuelChapterTpl:getChapterId(chapterCfg))
    self.data.lastChapterModeLevelId = _kiboDuelGroupTpl:getLevelId(chapterInfo[1])
  end
  return self.data.lastChapterModeLevelId
end

function this:setLastChapterModeLevelId(levelId)
  self.data.lastChapterModeLevelId = levelId
end

function this:getCurChallengeGroupId()
  return self.data.curChallengeGroupId
end

function this:setCurChallengeGroupId(groupId)
  self.data.curChallengeGroupId = groupId
end

function this:getCurPetDuelFormationPetGuids()
  return self:getPetDuelFormationPetGuids(self:getCurPetDuelFormationSlot())
end

function this:getCurPetDuelFormationHeroGuid()
  return self:getPetDuelFormationHeroGuid(self:getCurPetDuelFormationSlot())
end

function this:getCurPetDuelFormationHeroSkills()
  return self:getPetDuelFormationHeroSkills(self:getCurPetDuelFormationSlot())
end

function this:getKiBoDuelLevelInfo(levelId)
  return self.data.petDuelRecordInfo[levelId] or {}
end

function this:getIsSuccess(levelId)
  local levelInfo = self:getKiBoDuelLevelInfo(levelId)
  if not table.isEmpty(levelInfo) then
    return not math.isEmpty(levelInfo.success_time)
  end
  return false
end

function this:getKiBoDuelStar(levelId)
  local levelInfo = self:getKiBoDuelLevelInfo(levelId)
  if not table.isEmpty(levelInfo) then
    return L_CommonUtil.numberToBool(levelInfo.star)
  end
  return {}
end

function this:checkSkillCanUse(levelId, skillId)
  local kiBoDuelCfg = _kiBoDuelTpl:getTplById(levelId)
  local canUseSkillList = _kiBoDuelTpl:getSkillList(kiBoDuelCfg)
  return table.containsValue(canUseSkillList, skillId)
end

function this:getCanUseSkillNum()
  if not self.data.canUseSkillNum then
    self.data.canUseSkillNum = _gameConstTpl:getValue("KIBO_DUEL_FORMATION_CHAR_SKILL_NUM")
  end
  return self.data.canUseSkillNum
end

function this:getCanUseSkillPool()
  if not self.data.canUseSkillPool then
    self.data.canUseSkillPool = _gameConstTpl:getValue("KIBO_DUEL_CHAR_COMMONSKILL_POOL")
  end
  return self.data.canUseSkillPool
end

function this:getDefaultSkillIds(levelId)
  local defaultSkillNum = self:getCanUseSkillNum()
  local skillPoolList = self:getCanUseSkillPool()
  local skillIds = {}
  local kiBoDuelCfg = _kiBoDuelTpl:getTplById(levelId)
  local canUseSkillList = _kiBoDuelTpl:getSkillList(kiBoDuelCfg)
  for _, skillId in ipairs(skillPoolList) do
    if table.containsValue(canUseSkillList, skillId) then
      table.insert(skillIds, skillId)
    end
    if defaultSkillNum <= #skillIds then
      break
    end
  end
  return skillIds
end

function this:getDefaultSkillInfos(levelId)
  local defaultSkillNum = self:getCanUseSkillNum()
  local skillPoolList = self:getCanUseSkillPool()
  local skillInfos = {}
  local kiBoDuelCfg = _kiBoDuelTpl:getTplById(levelId)
  local canUseSkillList = _kiBoDuelTpl:getSkillList(kiBoDuelCfg)
  local startIndex = 701
  for _, skillId in ipairs(skillPoolList) do
    if table.containsValue(canUseSkillList, skillId) then
      table.insert(skillInfos, {
        skill_id = skillId,
        skill_lv = 1,
        skill_slot = startIndex,
        type = L_Const.ModuleGamingType.MGT_KIBO_DUEL
      })
      startIndex = startIndex + 1
    end
    if defaultSkillNum <= #skillInfos then
      break
    end
  end
  return skillInfos
end

function this:checkChapterModeUnlock(modeId, bShowTips)
  local modeInfo = _kiboDuelChapterTpl:getModeInfo(modeId)
  local tpl = modeInfo[1]
  local isComplete, results, lockIndex = L_ConditionManager:isComplete(_kiboDuelChapterTpl:getCondition(tpl))
  if not bShowTips then
    return isComplete
  end
  if not isComplete then
    local results = L_ConditionManager:getDescs(_kiboDuelChapterTpl:getCondition(tpl))
    L_FlyMsgManager:showNormalMsg(results[lockIndex])
    return false
  end
  return true
end

function this:checkChapterUnlock(chapterId, bShowTips)
  local chapterCfg = _kiboDuelChapterTpl:getTplById(chapterId)
  local modeInfo = _kiboDuelChapterTpl:getModeInfo(_kiboDuelChapterTpl:getModeId(chapterCfg))
  local lastChapterInfo = modeInfo[_kiboDuelChapterTpl:getIndex(chapterCfg) - 1]
  if lastChapterInfo then
    for _, levelId in ipairs(_kiboDuelChapterTpl:getKiBoDuelGroupId(lastChapterInfo)) do
      if not self:getIsSuccess(levelId) then
        if bShowTips then
          L_FlyMsgManager:showNormalMsg(L_WordsTpl:getValue("notice_petDuelStore_02"))
        end
        return false
      end
    end
  end
  local isComplete, results, lockIndex = L_ConditionManager:isComplete(_kiboDuelChapterTpl:getCondition(chapterCfg))
  if not bShowTips then
    return isComplete
  end
  if not isComplete then
    local results = L_ConditionManager:getDescs(_kiboDuelChapterTpl:getCondition(chapterCfg))
    L_FlyMsgManager:showNormalMsg(results[lockIndex])
    return false
  end
  return true
end

function this:checkChapterLevelUnlocked(levelId, bShowTips)
  local preCondition = _kiboDuelGroupTpl:getPreCondition(levelId)
  if not preCondition then
    return true
  end
  for _, v in ipairs(preCondition) do
    if not self:getIsSuccess(v) then
      if bShowTips then
        L_FlyMsgManager:showNormalMsg(L_WordsTpl:getValue("notice_petDuelStore_01"))
      end
      return false
    end
  end
  return true
end

local _cellWidth = 200
local _cellHeight = 100
local _widthDelta = 100
local _heightDelta = 50
local _heightSize = 5
local _startFixWidth = 100
local _endFixWidth = 0

function this:getChapterLevelPos(levelId)
  local cfg = _kiboDuelGroupTpl:getTplById(levelId)
  local offset = _kiboDuelGroupTpl:getOffset(cfg)
  local x = (offset[1] - 1) * (_cellWidth + _widthDelta) + _startFixWidth
  local y = ((_heightSize + 1) / 2 - offset[2]) * (_cellHeight + _heightDelta)
  return C_Vector3(x, y, 0)
end

function this:getChapterContentWidth(chapterId)
  local chapterColMax = _kiboDuelGroupTpl:getChapterColMax(chapterId)
  return (chapterColMax - 1) * (_cellWidth + _widthDelta) + _cellWidth + _startFixWidth
end

function this:getChapterLevelCellWidth()
  return _cellWidth
end

function this:checkPetValid(pet, levelId)
  if pet.id <= 0 then
    return true
  end
  local kiBoDuelCfg = _kiBoDuelTpl:getTplById(levelId)
  local levelType = _kiBoDuelTpl:getLevelType(kiBoDuelCfg)
  local systemKiBoList = _kiBoDuelTpl:getKiboList(kiBoDuelCfg)
  if pet.is_trial and not table.indexOf(systemKiBoList, pet.id, 1) then
    return false
  end
  if levelType == L_Const.kiBoDuelLevelType.mix then
    return true
  end
  if pet.is_trial and levelType == L_Const.kiBoDuelLevelType.player then
    return false
  end
  if not pet.is_trial and levelType == L_Const.kiBoDuelLevelType.system then
    return false
  end
  return true
end

function this:getTrialPetGuid(id)
  return self.data.trialPetGuids[id]
end

local nameEnumList = {
  "A",
  "B",
  "C",
  "D",
  "E",
  "F",
  "G",
  "H",
  "I",
  "J",
  "K",
  "L",
  "M",
  "N",
  "O",
  "P",
  "Q",
  "R",
  "S",
  "T",
  "U",
  "V",
  "W",
  "X",
  "Y",
  "Z"
}

function this:getPetName(data)
  local petInfo = {}
  local result = {}
  local checkRepeat = function(cfgId, name)
    local repeatNum = 0
    if petInfo[cfgId] then
      for _, v in ipairs(petInfo[cfgId]) do
        if v.name == name then
          repeatNum = repeatNum + 1
        end
      end
      return repeatNum
    else
      return repeatNum
    end
  end
  for index, v in ipairs(data) do
    if v.id <= 0 then
      table.insert(result, string.empty)
    elseif v.is_trial then
      local trialPetCfg = _trialPetTpl:getTplById(v.id)
      local petCfgId = _trialPetTpl:getTrialPet(trialPetCfg)
      local petCfg = petTpl:getTplById(petCfgId)
      local name = petTpl:getName(petCfg)
      local repeatNum = checkRepeat(petCfgId, name)
      if 0 < repeatNum then
        if repeatNum == 1 then
          result[petInfo[petCfgId][1].index] = name .. nameEnumList[repeatNum]
        end
        local finalName = name .. nameEnumList[repeatNum + 1]
        table.insert(petInfo[petCfgId], {name = name, index = index})
        table.insert(result, finalName)
      else
        petInfo[petCfgId] = {}
        table.insert(petInfo[petCfgId], {name = name, index = index})
        table.insert(result, name)
      end
    else
      local petItem = L_PetStore:getPetItem(v.id)
      if not petItem then
        table.insert(result, string.empty)
      else
        local repeatNum = checkRepeat(petItem:petCfgId(), petItem:getPetName())
        if 0 < repeatNum then
          if repeatNum == 1 then
            result[petInfo[petItem:petCfgId()][1].index] = petItem:getPetName() .. nameEnumList[repeatNum]
          end
          local finalName = petItem:getPetName() .. nameEnumList[repeatNum + 1]
          table.insert(petInfo[petItem:petCfgId()], {
            name = petItem:getPetName(),
            index = index
          })
          table.insert(result, finalName)
        else
          petInfo[petItem:petCfgId()] = {}
          table.insert(petInfo[petItem:petCfgId()], {
            name = petItem:getPetName(),
            index = index
          })
          table.insert(result, petItem:getPetName())
        end
      end
    end
  end
  return result
end

function this:getPetNameBySlot(slotIndex)
  local result = self:getPetName(self:getCurPetDuelFormationPetGuids())
  return result[slotIndex]
end

function this:getPetExpInfo()
  return self.data.petExpInfo
end

function this:resetPetExpInfo()
  self.data.petExpInfo = {}
end

function this:isLockKiBo(formationSlotId, slotIndex)
  local info = self:getPetDuelFormationGroupInfo(formationSlotId)
  return slotIndex <= info.lockSlot
end

return this
