local this = class("pageSpiritronStrength", G_UIPageBase)
local _battleInfoTpl = L_GameTpl:getBattleInfoTpl()
local _spiritronLevelTpl = L_GameTpl:getSpiritronLevelTpl()
local _spiritronTpl = L_GameTpl:getSpiritronTpl()
local commonItemTpl = L_GameTpl:getCommonItemTpl()
local spiritronRankTpl = L_GameTpl:getSpiritronRankTpl()
local gameTpl = L_GameTpl:getGameConstTpl()
local _wordsTpl = L_GameTpl:getWordsTpl()
local AddColor = L_GameUtil.fillColor
local Blue001 = L_Const.colorHtml.blue001
local ratio = gameTpl:getValue("WEAPON_LEVELUP_GOLD") / 10000
local AdvanceBgColor = C_Color(0.16470588235294117, 0.3607843137254902, 0.7725490196078432)

function this.bind()
  return {
    module_spiritronIcon = L_Const.ModuleInfo.CellIcon,
    txt_name = "",
    txt_level = "",
    txt_cost = "0",
    txt_skill = "",
    tips = "",
    tipsActive = false,
    advanceColor = C_Color.white,
    sliderValue_exp = 0,
    txt_exp = "",
    sliderValue_addExp = 0,
    titleNo2 = false,
    titleNo1 = false,
    advanceBtn = false,
    lvUpBtn = true,
    unlockDesText = "",
    unlockDesTextActive = false,
    oneSelectActvie = true,
    resetBtnActive = true,
    starUpBtnActive = false,
    cellSpiritronItem = L_Const.ModuleInfo.CellIcon,
    scrollList_property = {
      moduleName = "pages/spiritron/cellSpiritronProp"
    },
    module_currency = {
      moduleName = "modulePages/moduleCurrency"
    },
    module_sortWay = L_Const.ModuleInfo.FoYeFilterModule,
    expBookItem = L_Const.ModuleInfo.CellIcon,
    moduleCommonTop = {
      moduleName = "modulePages/moduleCommonTop"
    }
  }
end

function this.methods()
  return {
    onClick_reset = function(self)
      self:deselectAll()
    end,
    onClick_oneSelect = function(self)
      self:onClickAutoSelect()
    end,
    onClick_strength = function(self)
      self:onClickStrength()
    end,
    onClick_advanceBtn = function(self)
      L_UI:open("pageSpiritronAdvance", {
        weaponGuid = self._currGuid
      })
    end,
    onClick_starUpBtn = function(self)
      self:onClickStrength()
    end
  }
end

function this:preOpen(options)
  this.super.preOpen(self, options)
  local data = {
    name = L_WordsTpl:getValue("ui_systemMessage_23"),
    closeCurPage = function()
      L_UI:close(self.pageName)
    end
  }
  self.modules.moduleCommonTop:initModule(data)
  self._currGuid = options.weaponGuid
  L_SpiritronStore:listenCallFunc(L_SpiritronStore.event.refreshWeapon, self.refreshAll, self)
end

function this:close(options)
  this.super.close(self, options)
  L_SpiritronStore:unListenCallFunc(L_SpiritronStore.event.refreshWeapon, self.refreshAll)
end

function this:show(options)
  self:initPage()
end

function this:initPage()
  local tpl_sys = L_GameTpl:getSystemUnlockTpl():getTplById(L_SystemConst.enum.spiritronStrength)
  self.modules.module_currency:refreshRes(tpl_sys)
  local list = {
    L_Const.sortType.lv,
    L_Const.sortType.quality,
    L_Const.sortType.star
  }
  local func = function(type, order)
    self._sortParam = {type = type, order = order}
    self:updateSpiritronList()
  end
  self._sortParam = {
    type = L_Const.sortType.lv,
    order = L_Const.sortOrder.DESC
  }, self.modules.module_sortWay:initModule(list, func)
  self:refreshAll()
end

function this:refreshAll()
  if not L_SpiritronStore:getSpiritronItem(self._currGuid) then
    return
  end
  self:updateSpiritronInfo()
  self:updateSpiritronList()
  self:updateExpItemList()
  self:updateStrengthView()
  self:updateTip()
end

function this:updateSpiritronInfo()
  local spData = L_SpiritronStore:getSpiritronItem(self._currGuid)
  local spConf = L_ItemTplManager:getSpiritronItem(spData.spiritronId)
  self.bind.txt_name = spConf.name
  self.modules.module_spiritronIcon:setGeneralContent(L_Const.resType.spiritron, spData.spiritronId, {
    showStar = spData.star
  })
end

function this:getMaxLv()
  local spData = L_SpiritronStore:getSpiritronItem(self._currGuid)
  local rankData = spiritronRankTpl:getChildren(spData.spiritronId)
  return rankData[spData.rank].rankLevelLimit
end

function this:updateTip()
  local spData = L_SpiritronStore:getSpiritronItem(self._currGuid)
  local rankData = spiritronRankTpl:getChildren(spData.spiritronId)
  self.bind.tipsActive = true
  if spData.spiritronLv >= self:getMaxLv() then
    if spData.rank == #rankData then
      if L_Const.SpiritronFullStar > spData.star then
        self.bind.tips = _wordsTpl:getTplById("notice_spiritron_starup")
      else
        self.bind.tipsActive = false
        self.bind.tips = ""
      end
    else
      self.bind.tips = _wordsTpl:getTplById("notice_spiritron_levelmax")
    end
  elseif #self.modules.cellSpiritronItem <= 0 and 0 >= #self.modules.expBookItem then
    self.bind.tips = _wordsTpl:getTplById("notice_spiritron_nomaterial")
  else
    self.bind.tips = _wordsTpl:getTplById("notice_spiritron_levelup")
  end
  if self.bind.unlockDesTextActive then
    self.bind.tipsActive = false
  end
end

function this:updateSpiritronList()
  local currTableId = L_SpiritronStore:getSpiritronItem(self._currGuid).spiritronId
  local spiritronList = L_SpiritronStore:getSpiritronList()
  local spListData = {}
  for k, v in pairs(spiritronList) do
    if self._currGuid ~= v.guid then
      local conf = L_ItemTplManager:getSpiritronItem(v.spiritronId)
      local data = {
        mutiSelect = true,
        itemType = L_Const.resType.spiritron,
        guid = v.guid,
        selectCallback = function()
          self:updateStrengthView()
        end,
        star = v.star,
        level = v.spiritronLv,
        quality = conf.quality,
        id = v.spiritronId,
        lock = v.lock and 0 or 1,
        heroId = v.spiritronHero,
        isSame = v.spiritronId == currTableId and 1 or 0
      }
      table.insert(spListData, data)
    end
  end
  local isAsc = self._sortParam.order == L_Const.sortOrder.ASC
  if self._sortParam.type == L_Const.sortType.star then
    L_CommonUtil.multipleSortByKey(spListData, {
      "-heroId",
      "lock",
      "isSame",
      isAsc and "-star" or "star",
      "level",
      "-quality",
      "-id",
      "-guid"
    })
  elseif self._sortParam.type == L_Const.sortType.lv then
    L_CommonUtil.multipleSortByKey(spListData, {
      "-heroId",
      "lock",
      "isSame",
      isAsc and "-level" or "level",
      "star",
      "-quality",
      "-id",
      "-guid"
    })
  elseif self._sortParam.type == L_Const.sortType.quality then
    L_CommonUtil.multipleSortByKey(spListData, {
      "-heroId",
      "lock",
      "isSame",
      isAsc and "-quality" or "quality",
      "level",
      "-star",
      "-id",
      "-guid"
    })
  end
  self.bind.cellSpiritronItem:clear()
  self.bind.cellSpiritronItem:insert_array(spListData)
  self.bind.titleNo2 = 0 >= #self.modules.cellSpiritronItem
  self:updateSpiritronDisable()
end

function this:updateExpItemList()
  local data = {}
  for _, itemId in ipairs(L_Const.SpiritronExpItemIds) do
    local item = L_BagStore:getItem(itemId)
    if item and item.itemNum ~= 0 then
      table.insert(data, {
        mutiSelect = true,
        itemId = itemId,
        itemNum = item.itemNum,
        itemType = L_Const.resType.commonItem,
        selectCallback = function()
          self:updateStrengthView()
        end,
        validateSelectFunc = function(oldv, newv)
          if oldv < newv and self._showLv >= self:getMaxLv() then
            L_FlyMsgManager:showNormalMsg(_wordsTpl:getTplById("notice_spiritron_levelmax2"))
            return false
          end
          return true
        end
      })
    end
  end
  self.bind.titleNo1 = #data <= 0
  self.bind.expBookItem:clear()
  self.bind.expBookItem:insert_array(data)
end

function this:updateSpiritronDisable()
  local cExp, cStar = self:calculateExpAndStar()
  local spData = L_SpiritronStore:getSpiritronItem(self._currGuid)
  for _, module in ipairs(self.modules.cellSpiritronItem) do
    local thisSpData = L_SpiritronStore:getSpiritronItem(module.bind.guid)
    local disable = false
    disable = disable or thisSpData.spiritronId == spData.spiritronId and thisSpData.star + spData.star + cStar > L_Const.SpiritronFullStar
    disable = disable or thisSpData.spiritronId ~= spData.spiritronId and self._expOverFlow
    disable = disable and module:getSelectNum() <= 0
    disable = disable or thisSpData.lock
    disable = disable or thisSpData.spiritronHero ~= 0
    module:setDisable(disable)
  end
end

function this:updateStrengthView()
  local currSpData = L_SpiritronStore:getSpiritronItem(self._currGuid)
  local item = L_ItemTplManager:getSpiritronItem(currSpData.spiritronId)
  local cExp, cStar = self:calculateExpAndStar()
  self:setStars(currSpData.star, currSpData.star + cStar)
  local afterExp = _spiritronLevelTpl:getExpAll(_spiritronLevelTpl:getTplById(currSpData.spiritronLv, item.quality)) + currSpData.exp + cExp
  local afterTpl = _spiritronLevelTpl:getTplByExp(afterExp, item.quality)
  local afterLevel = _spiritronLevelTpl:getLv(afterTpl)
  local afterNeedExp = _spiritronLevelTpl:getExp(afterTpl)
  local exp = afterExp - _spiritronLevelTpl:getExpAll(_spiritronLevelTpl:getTplById(afterLevel, item.quality))
  self._showLv = afterLevel
  if afterLevel > currSpData.spiritronLv then
    self.bind.txt_level = AddColor(afterLevel, Blue001) .. "/" .. tostring(self:getMaxLv())
    self.bind.sliderValue_exp = 0
    if self._expOverFlow then
      local afterNeedExp = _spiritronLevelTpl:getExp(_spiritronLevelTpl:getTplById(afterLevel - 1, item.quality))
      self.bind.txt_exp = string.format("%s/%s", AddColor(afterNeedExp, Blue001), afterNeedExp)
      self.bind.sliderValue_addExp = 1
    else
      self.bind.txt_exp = string.format("%s/%s", AddColor(exp, Blue001), afterNeedExp)
      self.bind.sliderValue_addExp = exp / afterNeedExp
    end
  else
    self.bind.sliderValue_addExp = exp / afterNeedExp
    self.bind.sliderValue_exp = currSpData.exp / afterNeedExp
    self.bind.txt_level = AddColor(currSpData.spiritronLv, Blue001) .. "/" .. tostring(self:getMaxLv())
    if currSpData.spiritronLv >= self:getMaxLv() then
      self.bind.txt_exp = ""
    else
      self.bind.txt_exp = string.format("%s/%s", exp > currSpData.exp and AddColor(exp, Blue001) or exp, afterNeedExp)
    end
  end
  self.bind.go_maxLevel = afterLevel == self:getMaxLv()
  if self.bind.go_maxLevel then
    afterNeedExp = _spiritronLevelTpl:getExp(_spiritronLevelTpl:getTplById(afterLevel, item.quality))
    self.bind.txt_exp = string.format("%s/%s", AddColor(0, Blue001), afterNeedExp)
    self.bind.sliderValue_addExp = 0
  end
  local proList = {}
  local currPropertyList = L_SpiritronManager:getAttListByGuid(self._currGuid)
  local afterPropertyList = L_SpiritronManager:getConfigAttList(currSpData.spiritronId, afterLevel, currSpData.rank)
  for k, v in pairs(afterPropertyList) do
    local currStr = _battleInfoTpl:getShowPropertyTxt_spiritron(k, currPropertyList[k])
    local increaseStr = _battleInfoTpl:getShowIncreaseNum(k, v, currPropertyList[k])
    if v > currPropertyList[k] then
      currStr = currStr .. AddColor("+", Blue001) .. AddColor(increaseStr, Blue001)
    end
    table.insert(proList, {id = k, valueShowText = currStr})
  end
  L_SpiritronManager:sortAttrId(proList)
  for i, data in ipairs(proList) do
    data.bg = i % 2 == 1
  end
  self.bind.scrollList_property:clear()
  self.bind.scrollList_property:insert_array(proList)
  local needCost = math.floor(cExp * ratio)
  self.bind.txt_cost = self._currencyEnough and tostring(needCost) or AddColor(needCost, L_Const.colorHtml.red01)
  self:updateSpiritronDisable()
  self:checkPlayerLevelSatisified()
end

function this:checkPlayerLevelSatisified()
  local spData = L_SpiritronStore:getSpiritronItem(self._currGuid)
  local rankData = spiritronRankTpl:getChildren(spData.spiritronId)
  local rankTpl = rankData[spData.rank]
  local condition = spiritronRankTpl:getCondition(rankTpl)
  local bComplete = true
  if not table.isEmpty(condition) then
    bComplete = L_ConditionManager:singleIsComplete(condition)
    self.bind.unlockDesText = L_ConditionManager:getSingleDesc(condition)
  end
  local cExp, cStar = self:calculateExpAndStar()
  local bAdvanced = spData.spiritronLv >= self:getMaxLv() and #rankData ~= spData.rank and cStar <= 0
  local canLevelUp = spData.spiritronLv < self:getMaxLv()
  self.bind.unlockDesTextActive = not bComplete and bAdvanced
  if self.bind.unlockDesTextActive then
    self.bind.advanceBtn = false
    self.bind.lvUpBtn = false
    self.bind.oneSelectActvie = false
    self.bind.starUpBtnActive = not bAdvanced and not self.bind.unlockDesTextActive
    self.bind.resetBtnActive = not bAdvanced
  elseif not canLevelUp then
    self.bind.starUpBtnActive = not bAdvanced and not bComplete
    self.bind.advanceBtn = bAdvanced and not self.bind.starUpBtnActive
    self.bind.lvUpBtn = not bAdvanced and not self.bind.starUpBtnActive
    self.bind.oneSelectActvie = not bAdvanced and not self.bind.starUpBtnActive
    self.bind.resetBtnActive = not bAdvanced
  else
    self.bind.starUpBtnActive = not canLevelUp
    self.bind.advanceBtn = not canLevelUp
    self.bind.lvUpBtn = canLevelUp
    self.bind.oneSelectActvie = canLevelUp
    self.bind.resetBtnActive = canLevelUp
  end
end

function this:getSkillContent(star, isUpStar)
  local spData = L_SpiritronStore:getSpiritronItem(self._currGuid)
  local skill_new, valueList_new = L_SpiritronManager:getConfigSkill(spData.spiritronId, star)
  local skillValueList_txt = {}
  for i = 1, #valueList_new do
    if isUpStar then
      skillValueList_txt[i - 1] = AddColor(valueList_new[i], Blue001)
    else
      skillValueList_txt[i - 1] = valueList_new[i]
    end
  end
  return L_Lang:get(skill_new, skillValueList_txt)
end

function this:calculateExpAndStar()
  local addExp = 0
  local addStar = 0
  local curSpData = L_SpiritronStore:getSpiritronItem(self._currGuid)
  local currSpItemConf = L_ItemTplManager:getSpiritronItem(curSpData.spiritronId)
  for _, module in ipairs(self.modules.expBookItem) do
    local unitExp = self:getItemUnitExp(module.bind.itemId)
    addExp = addExp + module:getSelectNum() * unitExp
  end
  for _, module in ipairs(self.modules.cellSpiritronItem) do
    if 0 < module:getSelectNum() then
      local spItemData = L_SpiritronStore:getSpiritronItem(module.bind.guid)
      local spItemConf = L_ItemTplManager:getSpiritronItem(spItemData.spiritronId)
      addExp = addExp + _spiritronTpl:getReishiExp(_spiritronTpl:getTplById(spItemData.spiritronId))
      addExp = addExp + spItemData.exp
      addExp = addExp + _spiritronLevelTpl:getExpAll(_spiritronLevelTpl:getTplById(spItemData.spiritronLv, spItemConf.quality))
      if spItemData.spiritronId == curSpData.spiritronId then
        addStar = addStar + spItemData.star
      end
    end
  end
  local maxExp = _spiritronLevelTpl:getExpAll(_spiritronLevelTpl:getTplById(self:getMaxLv(), currSpItemConf.quality))
  local needExp = maxExp - _spiritronLevelTpl:getExpAll(_spiritronLevelTpl:getTplById(curSpData.spiritronLv, currSpItemConf.quality)) - curSpData.exp
  self._expOverFlow = addExp >= needExp
  self._starOverFlow = curSpData.star + addStar >= L_Const.SpiritronFullStar
  addExp = math.min(addExp, needExp)
  local needCost = addExp * ratio
  self._currencyEnough = needCost <= L_PlayerStore:getCurrencyNum(L_Const.currencyType.gold)
  return addExp, addStar
end

function this:setStars(cur, upStars)
  upStars = upStars or 0
  for i = 1, self.bindComponents.starCur.childCount do
    self.bindComponents.starCur:GetChild(i - 1).gameObject:ActiveTrans(i <= cur or i <= upStars)
  end
  for i = 1, self.bindComponents.starAdv.childCount do
    self.bindComponents.starAdv:GetChild(i - 1).gameObject:ActiveTrans(cur < i and i <= upStars)
  end
  self.bind.advanceColor = upStars and AdvanceBgColor or C_Color.white
  self.bind.txt_skill = self:getSkillContent(upStars or spData.star, upStars)
end

function this:intensifySuccess(preLv, preStar)
  local spData = L_SpiritronStore:getSpiritronItem(self._currGuid)
  local item = L_ItemTplManager:getSpiritronItem(spData.spiritronId)
  if preStar < spData.star then
    local data = {
      guid = self._currGuid,
      describe = self:getSkillContent(spData.star, true),
      callback = function()
        local spData = L_SpiritronStore:getSpiritronItem(self._currGuid)
        local rankData = spiritronRankTpl:getChildren(spData.spiritronId)
        if spData.spiritronLv >= rankData[spData.rank].rankLevelLimit and #rankData > spData.rank then
          local rankTpl = rankData[spData.rank]
          local condition = spiritronRankTpl:getCondition(rankTpl)
          local bComplete = true
          if not table.isEmpty(condition) then
            bComplete = L_ConditionManager:singleIsComplete(condition)
          end
          if bComplete then
            L_GameUtil.showCommonTip({
              txtContent = _wordsTpl:getTplById("notice_spiritron_levelmax"),
              txtTitle = _wordsTpl:getTplById("notice_spiritron_breakhint"),
              confirmCallback = function()
                L_UI:open("pageSpiritronAdvance", {
                  weaponGuid = self._currGuid
                })
              end
            })
          end
        end
      end
    }
    L_UI:open("pageSpiritronStrengthSuccess", data)
  end
end

function this:getAllSelects()
  local items = {}
  for _, module in ipairs(self.modules.expBookItem) do
    if module:getSelectNum() > 0 then
      table.insert(items, {
        id = module.bind.itemId,
        num = module:getSelectNum()
      })
    end
  end
  local spiritronData = {}
  for i, module in ipairs(self.modules.cellSpiritronItem) do
    if module:getSelectNum() > 0 then
      table.insert(spiritronData, module.bind.guid)
    end
  end
  return items, spiritronData
end

local TipKeys = {
  "notice_spiritron_useStar",
  "notice_spiritron_useLevel",
  "notice_spiritron_useQuality"
}

function this:onClickStrength()
  local items, spiritronData = self:getAllSelects()
  if #spiritronData == 0 and #items == 0 then
    return L_HeroManager:heroHintInfo(6)
  end
  if not self._currencyEnough then
    return L_HeroManager:heroHintInfo(1)
  end
  local data = {
    guid = self._currGuid,
    costs = spiritronData,
    cost_items = items
  }
  local tableTips = {}
  for i = 1, #spiritronData do
    local data = L_SpiritronStore:getSpiritronItem(spiritronData[i])
    local item = L_ItemTplManager:getSpiritronItem(data.spiritronId)
    tableTips[1] = tableTips[1] or 1 < data.star or nil
    tableTips[2] = tableTips[2] or 1 < data.spiritronLv or nil
    tableTips[3] = tableTips[3] or item.quality == 4 or nil
  end
  if table.isEmpty(tableTips) then
    self:spiritronStrength(data)
  else
    local str = ""
    for i = 1, 3 do
      if tableTips[i] then
        printf(i, TipKeys[i], _wordsTpl:getTplById(TipKeys[i]))
        str = str .. _wordsTpl:getValue(TipKeys[i]) .. "\n"
      end
    end
    str = str .. _wordsTpl:getValue("notice_spiritron_use")
    L_GameUtil.showCommonTip({
      txtContent = str,
      txtTitle = _wordsTpl:getTplById("notice_title_hint"),
      confirmCallback = function()
        self:spiritronStrength(data)
      end
    })
  end
end

function this:spiritronStrength(data)
  local currData = L_SpiritronStore:getSpiritronItem(self._currGuid)
  local lv = currData.spiritronLv
  local star = currData.star
  L_SpiritronStore:req_composeSpiritron(data, function()
    self:intensifySuccess(lv, star)
  end)
end

function this:getItemUnitExp(itemId)
  return commonItemTpl:getUseFunction(commonItemTpl:getTplById(itemId))[1]
end

function this:isSpiritronCanAutoSelect(guid)
  local spData = L_SpiritronStore:getSpiritronItem(guid)
  local spConf = L_ItemTplManager:getSpiritronItem(spData.spiritronId)
  return spData.spiritronLv == 1 and spData.star == 1 and spData.exp == 0 and not spData.lock and spData.spiritronHero == 0 and spData.spiritronId ~= L_SpiritronStore:getSpiritronItem(self._currGuid).spiritronId and spConf.quality == 2
end

function this:onClickAutoSelect()
  if self._showLv >= self:getMaxLv() then
    self._expOverFlow = false
    L_FlyMsgManager:showNormalMsg(_wordsTpl:getTplById("notice_spiritron_levelmax2"))
    return
  end
  self:autoSelect()
  local items, spiritronData = self:getAllSelects()
  if table.isEmpty(items) and table.isEmpty(spiritronData) then
    L_FlyMsgManager:showNormalMsg(_wordsTpl:getTplById("notice_spiritron_autoselect"))
  else
    self:updateStrengthView()
  end
end

function this:autoSelect()
  if self._showLv >= self:getMaxLv() then
    return
  end
  for _, module in ipairs(self.modules.expBookItem) do
    module:setSelectNum(0)
  end
  local cExp, cStar = self:calculateExpAndStar()
  local spData = L_SpiritronStore:getSpiritronItem(self._currGuid)
  local item = L_ItemTplManager:getSpiritronItem(spData.spiritronId)
  local selfLvExp = _spiritronLevelTpl:getExpAll(_spiritronLevelTpl:getTplById(spData.spiritronLv, item.quality))
  local tempExp = _spiritronLevelTpl:getExpAll(_spiritronLevelTpl:getTplById(self:getMaxLv(), item.quality)) - spData.exp - cExp - selfLvExp
  local allItemExp = 0
  local exp2NumMap = {}
  for _, module in ipairs(self.modules.expBookItem) do
    local unitExp = self:getItemUnitExp(module.bind.itemId)
    exp2NumMap[unitExp] = module.bind.itemNum
    allItemExp = allItemExp + unitExp * module.bind.itemNum
  end
  for exp, num in pairs(L_HeroManager:autoLvUp(exp2NumMap, tempExp)) do
    for _, module in ipairs(self.modules.expBookItem) do
      local unitExp = self:getItemUnitExp(module.bind.itemId)
      if unitExp == exp then
        module:setSelectNum(num or 0)
      end
    end
  end
  self:calculateExpAndStar()
end

function this:deselectAll()
  for _, module in ipairs(self.modules.cellSpiritronItem) do
    module:setSelectNum(0)
  end
  for _, module in ipairs(self.modules.expBookItem) do
    module:setSelectNum(0)
  end
end

return this
