local this = class("petReleaseManager")
local expReturnRaito = L_Config:getConfig("game", "PET_RETURN_RATIO") / 10000
local petExpItems = L_Config:getConfig("game", "PET_EXPITEMID")
local petFreeReward = L_Config:getConfig("game", "PET_FREEREWARD")
local petEggFreeReward = L_Config:getConfig("game", "PET_FREEEGGREWARD")
local petFreeRewardLimit = L_Config:getConfig("game", "PET_FREE_DAYLY_TIME")
local petFreeEggRewardLimit = L_Config:getConfig("game", "PET_FREEEGG_DAYLY_TIME")
local petTpl = L_GameTpl:getPetTpl()
local petLevelTpl = L_GameTpl:getPetLevelTpl()
local commonItemTpl = L_GameTpl:getCommonItemTpl()
local petRankTpl = L_GameTpl:getPetRankTpl()

function this:ctor()
  self.isReleaseMode = false
  self.selectGuids = {}
end

function this:setIsReleaseMode(isOn, isKeep)
  self.isReleaseMode = isOn
  if not isKeep then
    L_PetStore:resetSelectGuids()
  end
  L_PetStore:call(L_PetStore.event.setPetReleaseMode)
end

function this:getIsReleaseMode()
  return self.isReleaseMode
end

function this:dealQuickSelect(guids)
  local res = {}
  for k, guid in ipairs(guids) do
    local pet = L_PetStore:getPetItem(guid)
    if pet.is_lock ~= true and self:checkPetStatus(guid) then
      table.insert(res, guid)
    end
  end
  if 0 < #res then
    L_PetStore:setSelectGuids(res)
    return true
  end
  return false
end

function this:checkPetStatus(guid)
  local pet = L_PetStore:getPetItem(guid)
  if not pet then
    errorf("\229\174\160\231\137\169Guid" .. guid .. "\228\184\141\229\173\152\229\156\168PetStore\229\134\133", 2)
    return false
  end
  local tpl = petTpl:getTplById(pet.id)
  if not tpl then
    errorf("\229\174\160\231\137\169configId" .. pet.id .. "\228\184\141\229\173\152\229\156\168Pet\232\161\168\229\134\133", 2)
    return false
  end
  if not (petTpl:getIsRename(tpl) and math.isEmpty(pet:getHeroId())) or pet:isInMountRoulette() or not math.isEmpty(pet.work_build) then
    return false
  end
  return true
end

function this:dealSelectPet(guid)
  if self:isPetSelected(guid) then
    L_PetStore:setSelectReleasePet(guid)
    return
  end
  local pet = L_PetStore:getPetItem(guid)
  if pet.is_lock == true then
    local data = {
      txtContent = L_WordsTpl:getValue("ui_pet_release_lock_confirm"),
      confirmCallback = function()
        L_PetStore:req_lockPet(guid, false, function()
          self:dealSelectPet(guid)
        end)
      end
    }
    L_GameUtil.showCommonTip(data)
    return
  end
  if pet:getIsSpecialPet() and pet:hasFlashGene() then
    local data = {
      txtContent = L_WordsTpl:getValue("ui_pet_release_special_confirm_3"),
      confirmCallback = function()
        L_PetStore:setSelectReleasePet(guid)
      end
    }
    L_GameUtil.showCommonTip(data)
    return
  end
  if pet:getIsSpecialPet() then
    local data = {
      txtContent = L_WordsTpl:getValue("ui_pet_release_special_confirm_1"),
      confirmCallback = function()
        L_PetStore:setSelectReleasePet(guid)
      end
    }
    L_GameUtil.showCommonTip(data)
    return
  end
  if pet:hasFlashGene() then
    local data = {
      txtContent = L_WordsTpl:getValue("ui_pet_release_special_confirm_2"),
      confirmCallback = function()
        L_PetStore:setSelectReleasePet(guid)
      end
    }
    L_GameUtil.showCommonTip(data)
    return
  end
  if self:checkPetStatusAndTips(guid) then
    L_PetStore:setSelectReleasePet(guid)
  end
end

function this:checkPetStatusAndTips(guid)
  local pet = L_PetStore:getPetItem(guid)
  if not pet then
    errorf("\229\174\160\231\137\169Guid" .. guid .. "\228\184\141\229\173\152\229\156\168PetStore\229\134\133", 2)
    return false
  end
  local tpl = petTpl:getTplById(pet.id)
  if not tpl then
    errorf("\229\174\160\231\137\169configId" .. pet.id .. "\228\184\141\229\173\152\229\156\168Pet\232\161\168\229\134\133", 2)
    return false
  end
  if not petTpl:getIsRename(tpl) then
    L_FlyMsgManager:showNormalMsg(L_WordsTpl:getValue("ui_pet_release_block_name"))
    return false
  end
  if not math.isEmpty(pet:getHeroId()) then
    L_FlyMsgManager:showNormalMsg(L_WordsTpl:getValue("ui_pet_release_block_hero"))
    return false
  end
  if pet:isInMountRoulette() then
    L_FlyMsgManager:showNormalMsg(L_WordsTpl:getValue("ui_pet_release_block_mount"))
    return false
  end
  if pet.work_status ~= L_Const.PetStationedWorkStatusType.PSWST_NONE then
    L_FlyMsgManager:showNormalMsg(L_WordsTpl:getValue("ui_pet_release_block_building"))
    return false
  end
  return true
end

function this:isPetSelected(guid)
  local selectGuids = L_PetStore:getSelectGuids()
  return table.containsValue(selectGuids, guid)
end

function this:calculateReleaseRewards(guids)
  local res = {}
  for _, guid in ipairs(guids) do
    local expItems = self:calculateReleaseRewardForOnePet(guid)
    self:mergeRewards(res, expItems)
  end
  local freeItems = self:calculatePetFreeReward(#guids)
  self:mergeRewards(res, freeItems)
  local rewards = {}
  for itemId, count in pairs(res) do
    local orderWeight = 0
    if table.containsValue(petExpItems, itemId) then
      orderWeight = 100000000
    elseif itemId ~= petFreeReward[1] then
      orderWeight = 1000000
    end
    local tpl = commonItemTpl:getTplById(itemId)
    orderWeight = orderWeight + commonItemTpl:getRarity(tpl)
    table.insert(rewards, {
      orderWeight = orderWeight,
      itemId = itemId,
      itemNum = count,
      itemType = L_Const.resType.commonItem
    })
  end
  table.sort(rewards, function(a, b)
    return a.orderWeight > b.orderWeight
  end)
  printf("\232\174\161\231\174\151\230\148\190\231\148\159\229\165\150\229\138\177\231\187\147\230\158\156: ", rewards)
  return rewards
end

function this:mergeRewards(res, items)
  for itemId, count in pairs(items) do
    if res[itemId] == nil then
      res[itemId] = 0
    end
    res[itemId] = res[itemId] + count
  end
end

function this:calculateReleaseRewardForOnePet(guid)
  local pet = L_PetStore:getPetItem(guid)
  if not pet then
    return {}
  end
  local currentLevel = pet.lv
  local baseLevel = pet.base_lv
  local totalExp = 0
  local levelTpl
  for i = baseLevel, currentLevel - 1 do
    levelTpl = petLevelTpl:getTplById(i)
    totalExp = totalExp + petLevelTpl:getExp(levelTpl)
  end
  totalExp = totalExp + pet.exp
  totalExp = math.floor(totalExp * expReturnRaito)
  local res = self:calculateExpItems(totalExp)
  local rankItems = self:calculateRankBreakItems(guid)
  self:mergeRewards(res, rankItems)
  return res
end

function this:calculatePetFreeReward(addNum)
  local curNum = L_PetStore:getPetFreeRewardNum()
  local left = petFreeRewardLimit - curNum
  local num = math.min(left, addNum)
  local res = {}
  if num <= 0 then
    return res
  end
  res[petFreeReward[1]] = num * petFreeReward[2]
  return res
end

function this:calculateRankBreakItems(guid)
  local items = {}
  local pet = L_PetStore:getPetItem(guid)
  local rank = pet.rank
  local tpls = {}
  local previous = petRankTpl:getPreviousRankTpl(pet.id)
  while previous ~= nil and 0 < rank do
    table.insert(tpls, previous)
    previous = petRankTpl:getPreviousRankTpl(previous.petId)
    rank = rank - 1
  end
  for _, tpl in ipairs(tpls) do
    local breakItems = petRankTpl:getRankBreakthroughItem(tpl)
    for _, item in ipairs(breakItems) do
      if items[item[1]] == nil then
        items[item[1]] = 0
      end
      items[item[1]] = items[item[1]] + item[2]
    end
  end
  return items
end

function this:calculateExpItems(targetExp)
  local items = {}
  for _, v in ipairs(petExpItems) do
    local tpl_commonItem = commonItemTpl:getTplById(v)
    local expNum = commonItemTpl:getUseFunction(tpl_commonItem)[1]
    table.insert(items, {
      exp = expNum,
      count = 0,
      itemId = v
    })
  end
  table.sort(items, function(a, b)
    return a.exp > b.exp
  end)
  for i = 1, #items do
    local itemExp = items[i].exp
    while targetExp >= itemExp do
      targetExp = targetExp - itemExp
      items[i].count = items[i].count + 1
    end
  end
  local res = {}
  for _, item in pairs(items) do
    if item.count > 0 then
      res[item.itemId] = item.count
    end
  end
  return res
end

function this:getFreeEggRewards(guids)
  local curNum = L_PetStore:getFreeEggRewardNum()
  local addNum = #guids
  if curNum + addNum >= petFreeEggRewardLimit then
    return {}
  end
  local res = {
    {
      itemId = petEggFreeReward[1],
      itemType = L_Const.resType.commonItem,
      itemNum = petEggFreeReward[2] * addNum
    }
  }
  return res
end

function this:reqDeletePetEgg(eggList, callback)
  for _, v in pairs(eggList) do
    if L_PetStore:checkIsEggHatch(v) then
      L_FlyMsgManager:showNormalMsg(L_WordsTpl:getValue("ui_egg_release_hatch_block"))
      return
    end
  end
  local data = {egg_list = eggList}
  local rewards = self:getFreeEggRewards(eggList)
  if 0 < #rewards then
    L_GameUtil.showCommonTip({
      txtTitle = L_WordsTpl:getValue("ui_egg_release_confirm_title"),
      txtContent = L_WordsTpl:getValue("ui_egg_release_confirm_content"),
      confirmCallback = function()
        self:dealReleaseEggAction(data, callback)
      end,
      itemList = rewards
    })
  else
    local data_tip = {
      txtTitle = L_WordsTpl:getValue("ui_egg_release_confirm_title"),
      txtContent = L_WordsTpl:getValue("notice_bag_qibodan_fangsheng"),
      confirmCallback = function()
        self:dealReleaseEggAction(data, callback)
      end
    }
    L_GameUtil.showCommonTip(data_tip)
  end
end

function this:dealReleaseEggAction(data, callback)
  L_PetStore:req_removePetEgg(data, function(rspData, errorCode)
    if errorCode == L_Const.errorCode.ErrCodeSucc then
      if not table.isEmpty(rspData.rewards) then
        L_RewardManager:showPage(rspData.rewards, rspData.src)
      end
      if callback then
        callback()
      end
    end
  end)
end

return this
