local this = class("spiritronManager")
local _spiritronTpl = L_GameTpl:getSpiritronTpl()
local _spiritronLevelTpl = L_GameTpl:getSpiritronLevelTpl()
local _skillTpl = L_GameTpl:getSkillTpl()
local _skillLevelTpl = L_GameTpl:getSkillLevelTpl()
local _skillsubAttrupTpl = L_GameTpl:getSkillsubAttrupTpl()
local _spiritronRankTpl = L_GameTpl:getSpiritronRankTpl()

function this:ctor()
  self.spiritronPreviewList = {}
end

function this:getAllAttrByGuid(guid)
  local attrs = self:getAttListByGuid(guid)
  local spiritronItem = L_SpiritronStore:getSpiritronItem(guid)
  local id = spiritronItem.spiritronId
  local lv = spiritronItem.spiritronLv
  local rank = spiritronItem.rank
  local star = spiritronItem.star
  local skillList = self:getSpiritronSkills(id, lv, rank)
  for _, skillId in ipairs(skillList) do
    local tpl_skill = _skillTpl:getTplById(skillId)
    local skillType = _skillTpl:getSkillType(tpl_skill)
    if skillType == L_Const.skillFuncType.number then
      local tpl_skillLevel = _skillLevelTpl:getTplByIdAndLevel(skillId, star)
      local subSkillId = _skillLevelTpl:getSubSkillId(tpl_skillLevel)
      local tpl_skillSub = _skillsubAttrupTpl:getTplById(subSkillId)
      local attDic_tmp = _skillsubAttrupTpl:getAttributeList(tpl_skillSub)
      for k2, v2 in pairs(attDic_tmp) do
        attrs[k2] = (attrs[k2] or 0) + v2
      end
    end
  end
  return attrs
end

function this:getAllAttrByConfigId(configId)
  local attrs = _spiritronTpl:getProperty(configId)
  local skillList = self:getSpiritronSkills(configId)
  for _, skillId in ipairs(skillList) do
    local tpl_skill = _skillTpl:getTplById(skillId)
    local skillType = _skillTpl:getSkillType(tpl_skill)
    if skillType == L_Const.skillFuncType.number then
      local tpl_skillLevel = _skillLevelTpl:getTplByIdAndLevel(skillId)
      local subSkillId = _skillLevelTpl:getSubSkillId(tpl_skillLevel)
      local tpl_skillSub = _skillsubAttrupTpl:getTplById(subSkillId)
      local attDic_tmp = _skillsubAttrupTpl:getAttributeList(tpl_skillSub)
      for k2, v2 in pairs(attDic_tmp) do
        attrs[k2] = (attrs[k2] or 0) + v2
      end
    end
  end
  return attrs
end

function this:getAttListByGuid(guid)
  local spiritronItem = L_SpiritronStore:getSpiritronItem(guid)
  if not spiritronItem then
    printf("\228\184\141\229\173\152\229\156\168\231\129\181\229\173\144guid ", guid)
  end
  return self:getAttListByGuidByItem(spiritronItem)
end

function this:getAttListByGuidByItem(spiritronItem)
  local id = spiritronItem.spiritronId
  local lv = spiritronItem.spiritronLv
  local rank = spiritronItem.rank
  return self:getConfigAttList(id, lv, rank)
end

function this:getConfigAttList(id, level, rank)
  level = level or 1
  rank = rank or 1
  return _spiritronTpl:getProperty(id, level, rank)
end

function this:getSkillDescByGuid(guid)
  local spiritronItem = L_SpiritronStore:getSpiritronItem(guid)
  return self:getSkillDescByGuidByitem(spiritronItem)
end

function this:getSkillDescByGuidByitem(spiritronItem)
  local id = spiritronItem.spiritronId
  local star = spiritronItem.star
  return self:getConfigSkillDesc(id, star)
end

function this:getConfigSkillDesc(id, star)
  star = star or 1
  local skillId = _spiritronTpl:getSkillId(id)
  if skillId then
    return L_GameUtil.getSkillDesc(skillId, star)
  end
end

function this:getConfigSkill(id, star)
  return _spiritronTpl:getSkill(id, star)
end

function this:getExpMax(id, lv)
  local item = L_ItemManager:parseSpiritronItem(id)
  local tpl = _spiritronLevelTpl:getTplById(lv, item.quality)
  return _spiritronLevelTpl:getExp(tpl)
end

function this:getIsMaxLevel(guid)
  local spiritronItem = L_SpiritronStore:getSpiritronItem(guid)
  local item = L_ItemManager:parseSpiritronItem(spiritronItem.spiritronId)
  local spiritronLevelTpl = L_GameTpl:getSpiritronLevelTpl()
  local tpl = spiritronLevelTpl:getTplById(spiritronItem.spiritronLv, item.quality)
  return spiritronItem.spiritronLv >= spiritronLevelTpl:getMaxLevel(tpl)
end

function this:getSpiritronSkills(cfgId, level, rank)
  local skillList = {}
  local tpl = _spiritronTpl:getTplById(cfgId)
  if tpl then
    table.insert(skillList, _spiritronTpl:getReishiSkill(tpl))
  end
  return skillList
end

function this:canSpiritronAdvance(guid)
  local spirit = L_SpiritronStore:getSpiritronItem(guid)
  if spirit then
    local rankConfs = _spiritronRankTpl:getChildren(spirit.spiritronId)
    if L_Const.SpiritronFullStar > spirit.rank and spirit.spiritronLv == rankConfs[spirit.rank].rankLevelLimit then
      local itemList = rankConfs[spirit.rank].rankUpItem
      for i = 1, #itemList do
        if itemList[i][2] > L_BagStore:getItemNum(itemList[i][1]) then
          return true, false
        end
      end
      if L_PlayerStore:getCurrencyNum(L_Const.currencyType.gold) < rankConfs[spirit.rank].rankUpCoin then
        return true, false
      end
      return true, true
    end
  end
  return false, false
end

function this:canUpgrade()
end

function this:getPreviewSpiritronData(spiritronId, isMaxLevel)
  local list = self.spiritronPreviewList
  local guid = spiritronId * 10
  if isMaxLevel then
    guid = guid + 1
  end
  local spiritron = list[guid]
  if spiritron == nil then
    spiritron = L_SpiritronStore:createSpiritronData(guid)
    spiritron.spiritronId = spiritronId
    spiritron.spiritronHero = 0
    self:initSpiritronDataAll(spiritron, isMaxLevel)
    list[guid] = spiritron
  end
  return spiritron
end

function this:initSpiritronDataAll(spiritron, isMaxLevel)
  if isMaxLevel then
    local rankData = _spiritronRankTpl:getChildren(spiritron.spiritronId)
    spiritron.rank = #rankData
    spiritron.spiritronLv = rankData[spiritron.rank].rankLevelLimit
    spiritron.star = L_Const.SpiritronFullStar
    spiritron.exp = 0
    spiritron.lock = false
  else
    spiritron.rank = 1
    spiritron.spiritronLv = 1
    spiritron.star = 1
    spiritron.exp = 0
    spiritron.lock = false
  end
end

function this:sortAttrId(datas)
  table.sort(datas, function(a, b)
    local aw = a.id == 5 and 0 or a.id
    local bw = b.id == 5 and 0 or b.id
    return aw < bw
  end)
end

function this:getSpiritronItem(spiritronGuid, isPreview)
  if isPreview then
    local isMaxLevel = spiritronGuid % 10 == 1
    return self:getPreviewSpiritronData(math.floor(spiritronGuid / 10), isMaxLevel)
  else
    return L_SpiritronStore:getSpiritronItem(spiritronGuid)
  end
end

function this:getMaxLevel(spiritGuid, isPreview)
  local spiritronRankTpl = L_GameTpl:getSpiritronRankTpl()
  local spData = self:getSpiritronItem(spiritGuid, isPreview)
  local rankData = spiritronRankTpl:getChildren(spData.spiritronId)
  return rankData[spData.rank].rankLevelLimit
end

function this:getMaxLevelByRank(spiritGuid, rank)
  local spiritronRankTpl = L_GameTpl:getSpiritronRankTpl()
  local spData = L_SpiritronStore:getSpiritronItem(spiritGuid)
  local rankData = spiritronRankTpl:getChildren(spData.spiritronId)
  return rankData[rank].rankLevelLimit
end

function this:getStarUpSelectItem(selectItems, targetGuid)
  local curSpData = L_SpiritronStore:getSpiritronItem(targetGuid)
  local addStar = 0
  for k, item in pairs(selectItems) do
    if item.itemType == L_Const.resType.commonItem then
      addStar = addStar + item.itemSelectNum
    end
    if item.itemType == L_Const.resType.spiritron then
      local spData = L_SpiritronStore:getSpiritronItem(item.guid)
      addStar = addStar + spData.star
    end
  end
  local afterChangeStar = curSpData.star + addStar
  local overFlow = afterChangeStar > L_Const.SpiritronFullStar
  return addStar, afterChangeStar, overFlow
end

function this:getLevelUpSelectItemExp(selectItems, targetGuid)
  local goldRatio = L_GameTpl:getGameConstTpl():getValue("WEAPON_LEVELUP_GOLD") / 10000
  local spiritLevelTpl = L_GameTpl:getSpiritronLevelTpl()
  local addExp = 0
  local curSpData = L_SpiritronStore:getSpiritronItem(targetGuid)
  local currSpItemConf = L_ItemTplManager:getSpiritronItem(curSpData.spiritronId)
  local itemExp = 0
  local spiritExp = 0
  for k, item in pairs(selectItems) do
    if item.itemType == L_Const.resType.commonItem then
      local unitExp = self:getItemUnitExp(item.itemId)
      local exp = item.itemSelectNum * unitExp
      itemExp = itemExp + exp
    end
    if item.itemType == L_Const.resType.spiritron then
      local exp, gold = self:getSpiritUnitExp(item.guid)
      spiritExp = spiritExp + exp
    end
  end
  addExp = itemExp + spiritExp
  local maxLevel = self:getMaxLevel(targetGuid)
  local maxExp = spiritLevelTpl:getExpAll(spiritLevelTpl:getTplById(maxLevel, currSpItemConf.quality))
  local needExp = maxExp - spiritLevelTpl:getExpAll(spiritLevelTpl:getTplById(curSpData.spiritronLv, currSpItemConf.quality)) - curSpData.exp
  local expOverFlow = addExp >= needExp
  local overExp = addExp - needExp
  addExp = math.min(addExp, needExp)
  local gold = math.floor(addExp * goldRatio)
  return addExp, gold, expOverFlow, overExp
end

function this:getItemUnitExp(itemId)
  local commonItemTpl = L_GameTpl:getCommonItemTpl()
  return commonItemTpl:getUseFunction(commonItemTpl:getTplById(itemId))[1]
end

function this:getSpiritUnitExp(spiritGuid)
  local goldRatio = L_GameTpl:getGameConstTpl():getValue("WEAPON_LEVELUP_GOLD") / 10000
  local serverData = L_SpiritronStore:getSpiritronItem(spiritGuid)
  local currSpItemConf = L_ItemTplManager:getSpiritronItem(serverData.spiritronId)
  local spiritLevelTpl = L_GameTpl:getSpiritronLevelTpl()
  local levelTpl = spiritLevelTpl:getTplById(serverData.spiritronLv, currSpItemConf.quality)
  local expAll = spiritLevelTpl:getExpAll(levelTpl) + serverData.exp
  local ratio = L_Config:getConfig("game", "SPIRITRON_EXP_RATIO") / 10000
  local total = currSpItemConf.reishiExp + expAll * ratio
  local gold = currSpItemConf.reishiExp * goldRatio
  return total, gold
end

function this:getSpiritsForAutoLevelSelect(filterQuality, targetGuid)
  filterQuality = filterQuality or 100000
  local spiritronList = L_SpiritronStore:getSpiritronList()
  local spListData = {}
  for k, v in pairs(spiritronList) do
    local conf = L_ItemTplManager:getSpiritronItem(v.spiritronId)
    if math.isEmpty(v.spiritronHero) and not v.lock and filterQuality >= conf.quality and targetGuid ~= v.guid then
      local order = v.spiritronLv * 100000000
      order = order + v.star * 1000000
      order = order + conf.quality * 1000
      local exp = self:getSpiritUnitExp(v.guid)
      local data = {
        itemType = L_Const.resType.spiritron,
        guid = v.guid,
        order = order,
        star = v.star,
        level = v.spiritronLv,
        quality = conf.quality,
        id = v.spiritronId,
        lock = v.lock and 0 or 1,
        heroId = v.spiritronHero,
        exp = exp
      }
      table.insert(spListData, data)
    end
  end
  table.sort(spListData, function(a, b)
    if a.order == b.order then
      return a.id < b.id
    end
    return a.order < b.order
  end)
  return spListData
end

function this:getItemsForAutoStarSelect(targetGuid)
  local currSpData = L_SpiritronStore:getSpiritronItem(targetGuid)
  local spiritronList = L_SpiritronStore:getSpiritronList()
  local selectItems = {}
  local tmpSpiritronList = {}
  for k, v in pairs(spiritronList) do
    if math.isEmpty(v.spiritronHero) and not v.lock and v.spiritronId == currSpData.spiritronId and targetGuid ~= v.guid then
      local order = v.spiritronLv * 100000000
      order = order + v.star * 1000000
      table.insert(tmpSpiritronList, {
        guid = v.guid,
        order = order,
        exp = v.exp
      })
    end
  end
  table.sort(tmpSpiritronList, function(a, b)
    if a.order == b.order then
      return a.exp < b.exp
    end
    return a.order < b.order
  end)
  for k, v in pairs(tmpSpiritronList) do
    local _, afterStar, _ = self:getStarUpSelectItem(selectItems, targetGuid)
    if 4 <= #selectItems or afterStar >= L_Const.SpiritronFullStar then
      break
    end
    table.insert(selectItems, {
      itemType = L_Const.resType.spiritron,
      guid = v.guid,
      itemSelectNum = 1
    })
  end
  local _, afterStar, _ = self:getStarUpSelectItem(selectItems, targetGuid)
  if #selectItems < 4 and afterStar < L_Const.SpiritronFullStar then
    local spiritronTpl = L_GameTpl:getSpiritronTpl()
    local tpl = spiritronTpl:getTplById(currSpData.spiritronId)
    local starItems = L_Config:getConfig("game", "SPIRITRON_STAR_ITEM")
    local rarity = spiritronTpl:getRarity(tpl)
    local itemId = starItems[rarity]
    local item = L_BagStore:getItem(itemId)
    if item and item.itemNum > 0 then
      table.insert(selectItems, {
        itemType = L_Const.resType.commonItem,
        itemId = itemId,
        itemSelectNum = math.min(item.itemNum, L_Const.SpiritronFullStar - afterStar)
      })
    end
  end
  return selectItems
end

function this:getAdvancedSelectItem(selectItems)
  local items = {}
  local spiritronData = {}
  for _, item in ipairs(selectItems) do
    if item.itemType == L_Const.resType.commonItem then
      table.insert(items, {
        id = item.itemId,
        num = item.itemSelectNum
      })
    end
    if item.itemType == L_Const.resType.spiritron then
      table.insert(spiritronData, item.guid)
    end
  end
  return items, spiritronData
end

function this:openSpiritSwitch(options)
  options = options or {}
  options.hideBg = L_UI:checkPageOpen("pageHero")
  L_UI:open("pageHeroSpiritSwitch", options)
end

function this:openSpiritUpgrade(options)
  options = options or {}
  options.hideBg = L_UI:checkPageOpen("pageHero")
  L_UI:open("pageHeroSpiritUpgrade", options)
end

function this:getSpiritStoryRedInfo(spId)
  local conf = _spiritronTpl:getTplById(spId)
  if math.isEmpty(_spiritronTpl:getStory(conf)) then
    return false
  end
  local isComplete, _, _ = L_ConditionManager:isComplete(_spiritronTpl:getStoryLock(conf))
  if not isComplete then
    return false
  end
  return not L_SpiritronStore:isSpiritStoryPlayed(spId)
end

return this
