local this = class("moduleBattleHeroSkillBtn", G_UIModuleBase)
local C_EMultiSkillNoticeOperateType = CS.Lens.Gameplay.Modules.BigWorld.EMultiSkillNoticeOperateType
local C_ESwitchSkillState = CS.Lens.Gameplay.Modules.BigWorld.ESwitchSkillState
local C_ESkillEventType = CS.Lens.Gameplay.Modules.BigWorld.ESkillEventType
local _skillTpl = L_GameTpl:getSkillTpl()
local _skillSubLogicTpl = L_GameTpl:getSkillsubLogicTpl()

function this.bind()
  return {
    img_skill1 = "",
    go_chargeRoot = false,
    fill_multiSkill = 0,
    rot_multiSkill = C_Vector3.zero,
    go_multiSkill = false,
    fill_switchSkill = 0,
    rot_switchSkill = C_Vector3.zero,
    go_switchSkill = false,
    go_skillCanUseEft = false,
    go_skillCd = false,
    txt_skillCd = "0",
    fill_blackMaskSkill = 0,
    fill_whiteMaskSkill = 0,
    rotate_whiteMask2Skill = C_Vector3.zero,
    fill_whiteMask2Skill = 0
  }
end

function this.methods()
  return {
    onClick_skill = function(self)
      L_PlayerManager:fireSkill()
    end
  }
end

function this:open()
  self.data = {
    operateType = nil,
    skillShowResponse = false,
    multiSkillId = nil,
    coolDownCount = 0
  }
  self.updateHandle = handler(self, self.update)
  C_UpdateSource.AddUpdateEventHandler(self.updateHandle, "moduleBattleControl.moduleBattleHeroSkillBtn.update")
  L_PlayerManager:addListener(L_PlayerManager.event.setMainControl, self.setMainControl, self)
  L_BattleDataManager:addListener(L_BattleDataManager.event.onCastSkill, self.onEvent_onCastSkill, self)
  L_BattleDataManager:addListener(L_BattleDataManager.event.multiSkillNotice, self.onEvent_onMultiSkillNotice, self)
  L_BattleDataManager:addListener(L_BattleDataManager.event.skillStopNotice, self.onEvent_skillStopNotice, self)
  L_BattleDataManager:addListener(L_BattleDataManager.event.skillEventNotice, self.onEvent_skillEventNotice, self)
  L_BattleDataManager:addListener(L_BattleDataManager.event.refreshSkillIcon, self.switchSkill, self)
  L_BattleDataManager:addListener(L_BattleDataManager.event.switchSkillNotice, self.onEvent_switchSkillNotice, self)
  L_BattleDataManager:addListener(L_BattleDataManager.event.refreshPetSkill, self.switchSkill, self)
  self:refreshESkillNotice()
  self:refreshSkillIcon()
end

function this:show()
  self.data.multiSkillId = nil
  self:resetTimer()
  self.bindComponents.multiAnim:Stop()
  self.bind.go_multiSkill = false
  self.lastChargeCount = nil
  self.bPlayedAnim = false
end

function this:close()
  C_UpdateSource.RemoveUpdateEventHandler(self.updateHandle)
  self:resetTimer()
  L_PlayerManager:removeListener(L_PlayerManager.event.setMainControl, self.setMainControl, self)
  L_BattleDataManager:removeListener(L_BattleDataManager.event.refreshAttackStatus, self.onEvent_refreshAttackStatus, self)
  L_BattleDataManager:removeListener(L_BattleDataManager.event.onCastSkill, self.onEvent_onCastSkill, self)
  L_BattleDataManager:removeListener(L_BattleDataManager.event.multiSkillNotice, self.onEvent_onMultiSkillNotice, self)
  L_BattleDataManager:removeListener(L_BattleDataManager.event.skillStopNotice, self.onEvent_skillStopNotice, self)
  L_BattleDataManager:removeListener(L_BattleDataManager.event.skillEventNotice, self.onEvent_skillEventNotice, self)
  L_BattleDataManager:removeListener(L_BattleDataManager.event.refreshSkillIcon, self.switchSkill, self)
  L_BattleDataManager:removeListener(L_BattleDataManager.event.switchSkillNotice, self.onEvent_switchSkillNotice, self)
  L_BattleDataManager:removeListener(L_BattleDataManager.event.refreshPetSkill, self.switchSkill, self)
end

function this:onEvent_onCastSkill(args)
  if not self.data.skillShowResponse then
    return
  end
  local skillId = args.intArg
  local mainHero = L_PlayerManager:getMainControlEntity()
  if mainHero == nil then
    return
  end
  local skill = mainHero:getCsEntity().data.skillProperty:GetSkillBySlot(L_Const.C_ESkillSlotType.Skill2)
  if skill and skill.id == skillId then
    self.data.multiSkillId = skillId
    self:doShowStart()
  elseif self.data.multiSkillId and self.data.multiSkillId ~= skillId then
    self:doShowEnd()
  end
end

function this:onEvent_onMultiSkillNotice(args)
  if self.data.multiSkillId == nil then
    return
  end
  self.data.operateType = args.oprateType
  self.data.multiSkillId = args.skillId
  if self.data.operateType == C_EMultiSkillNoticeOperateType.Start then
    self:doSkillStart()
  elseif self.data.operateType == C_EMultiSkillNoticeOperateType.End then
    self:doShowEnd()
  elseif self.data.operateType == C_EMultiSkillNoticeOperateType.Update then
    self:refreshMutilSkillFill(args.skillFill)
  elseif self.data.operateType == C_EMultiSkillNoticeOperateType.Use then
    self:doShowUse()
  end
end

function this:onEvent_skillStopNotice(args)
  if args.intArg == self.data.multiSkillId then
    self:doShowEnd()
  end
end

function this:onEvent_skillEventNotice(args)
  if args.curSkillId == self.data.multiSkillId and args.type == C_ESkillEventType.InterruptSkill then
    self:doShowEnd()
  end
end

function this:onEvent_switchSkillNotice(args)
  if args.switchSkillState == C_ESwitchSkillState.Start then
    self:resetTimer()
    self.bind.go_switchSkill = true
    self.bind.fill_multiSkill = 1
    self.bind.rot_multiSkill = C_Vector3(0, 0, 0)
    self.bindComponents.switchAnim:Stop()
    self.bindComponents.switchAnim:Play("anim_battle_skill_response_ready")
  elseif args.switchSkillState == C_ESwitchSkillState.Update then
    self.bind.rot_switchSkill = C_Vector3(0, 0, 360 * args.skillFill)
    self.bind.fill_switchSkill = args.skillFill
  elseif args.switchSkillState == C_ESwitchSkillState.End then
    self.bindComponents.switchAnim:Play("anim_battle_skill_response_finish")
    self:delaySwitchSkillHide(0.2)
  end
end

function this:refreshMutilSkillFill(percent)
  self.bind.fill_multiSkill = 1 - percent
  self.bind.rot_multiSkill = C_Vector3(0, 0, 360 * (1 - percent))
end

function this:doSkillStart()
  self.bindComponents.multiAnim:Stop()
  self.bindComponents.multiAnim:Play("anim_battle_skill_response_ready")
end

function this:doShowStart()
  self.bind.go_multiSkill = true
  self.bind.fill_multiSkill = 1
  self.bind.rot_multiSkill = C_Vector3(0, 0, 0)
end

function this:delayMultiHide(delayTime)
  self.multiSkillTimer = Timer.once(delayTime, function()
    self.bind.go_multiSkill = false
  end)
end

function this:delaySwitchSkillHide(delayTime)
  self.switchSkillTimer = Timer.once(delayTime, function()
    self.bind.go_switchSkill = false
  end)
end

function this:resetTimer()
  if self.multiSkillTimer ~= nil then
    Timer.remove(self.multiSkillTimer)
    self.multiSkillTimer = nil
  end
  if self.switchSkillTimer ~= nil then
    Timer.remove(self.switchSkillTimer)
    self.switchSkillTimer = nil
  end
end

function this:doShowUse()
  self.data.multiSkillId = nil
  self:resetTimer()
  self.bindComponents.multiAnim:Stop()
  self.bindComponents.multiAnim:Play("anim_battle_skill_response_finish")
  self:delayMultiHide(0.25)
end

function this:doShowEnd()
  if self.data.multiSkillId == nil then
    return
  end
  self.data.multiSkillId = nil
  self:resetTimer()
  self.bindComponents.multiAnim:Stop()
  self.bindComponents.multiAnim:Play("anim_battle_skill_response_failed")
  self:delayMultiHide(0.2)
end

function this:setMainControl()
  self:refreshSkillIcon()
  self:refreshESkillNotice()
  self.bInit = false
end

function this:switchSkill(args)
  self:refreshSkillIcon()
  self:refreshESkillNotice()
end

function this:refreshESkillNotice()
  self.data.multiSkillId = nil
  self:resetTimer()
  self.bind.go_multiSkill = false
  local hero = L_PlayerManager:getMainHeroEntity()
  if not hero then
    return
  end
  local skill = hero:getCsEntity().data.skillProperty:GetSkillBySlot(L_Const.C_ESkillSlotType.Skill2)
  self.data.skillShowResponse = false
  if skill then
    self.data.skillShowResponse = _skillTpl:getSkillShowResponse(_skillTpl:getTplById(skill.id))
    self.data.coolDownCount = _skillSubLogicTpl:getCoolDownCount(_skillSubLogicTpl:getTplById(skill.id))
  end
  self:refreshChargeInfo()
  self.bPlayedAnim = false
end

function this:refreshChargeInfo()
  if self.data.coolDownCount <= 0 then
    self.bind.go_chargeRoot = false
    return
  end
  self.lastChargeCount = nil
  self.bind.go_chargeRoot = true
  self.chargeChildInfo = {}
  self.chargeChildAnim = {}
  for i = 1, self.bindComponents.rectChargeRoot.transform.childCount do
    local child = self.bindComponents.rectChargeRoot.transform:GetChild(i - 1)
    if i <= self.data.coolDownCount then
      table.insert(self.chargeChildInfo, child.gameObject)
      table.insert(self.chargeChildAnim, child:GetComponent(typeof(C_Animation)))
      L_CommonUtil.setObjActive(child.gameObject, true)
    else
      L_CommonUtil.setObjActive(child.gameObject, false)
    end
  end
  local cellDegree = (360 - 10 * self.data.coolDownCount) / self.data.coolDownCount
  for i = 1, #self.chargeChildInfo do
    local child = self.chargeChildInfo[i]
    child.transform:GetComponent(typeof(C_LImage)).fillAmount = cellDegree / 360
    child.transform:GetChild(0):GetComponent(typeof(C_LImage)).fillAmount = cellDegree / 360
    child.transform.localEulerAngles = C_Vector3(0, 0, -(5 + (i - 1) * (cellDegree + 10)))
  end
  local hero = L_PlayerManager:getMainHeroEntity()
  if not hero then
    return
  end
  local skill = hero:getCsEntity().data.skillProperty:GetSkillBySlot(L_Const.C_ESkillSlotType.Skill2)
  if not skill then
    return
  end
  for i = 1, #self.chargeChildInfo do
    if i > skill.coolDown.currentChargeCount then
      self.chargeChildAnim[i]:Play("anim_battle_skill_charge_init_hide")
    else
      self.chargeChildAnim[i]:Play("anim_battle_skill_charge_init_show")
    end
  end
end

function this:refreshSkillIcon()
  local hero = L_PlayerManager:getMainHeroEntity()
  if not hero then
    return
  end
  local skill = hero:getCsEntity().data.skillProperty:GetSkillBySlot(L_Const.C_ESkillSlotType.Skill2)
  if skill then
    local skillId = skill.id
    local tpl = _skillTpl:getTplById(skillId)
    local icon = _skillTpl:getIcon(tpl)
    self.bind.img_skill1 = icon
  end
  self.bind.go_switchSkill = hero:getCsEntity().data.skillProperty:GetInTimerBySlot(L_Const.C_ESkillSlotType.Skill2)
end

function this:update()
  local hero = L_PlayerManager:getMainHeroEntity()
  if not hero then
    return
  end
  local skillProperty = hero:getCsEntity().data.skillProperty
  local go_skillCd = false
  local skill = skillProperty:GetSkillBySlot(L_Const.C_ESkillSlotType.Skill2)
  if not self.bind.go_multiSkill and skill then
    local coolDown = skill.coolDown
    local ready = coolDown:Ready()
    if ready and (coolDown.currentChargeCount >= coolDown.chargeMaxCount or self.data.coolDownCount <= 0) then
      self.bPlayedAnim = false
    else
      go_skillCd = true
      local coolTime = C_MyFloatUtility.GetFloat(coolDown.coolTime)
      local coolDownTime = C_MyFloatUtility.GetFloat(coolDown.coolDown)
      self.bind.txt_skillCd = tostring(math.round(coolTime))
      if coolDown.currentChargeCount == 0 then
        self.bind.fill_blackMaskSkill = coolTime / coolDownTime
        if not self.bPlayedAnim then
          self.bindComponents.skillAnim:Play("anim_battle_skill_cd_black", 1)
          self.bPlayedAnim = true
        end
      else
        self.bind.fill_whiteMaskSkill = 1 - coolTime / coolDownTime
        self.bind.rotate_whiteMask2Skill = C_Vector3(0, 0, 360 - 360 * (1 - coolTime / coolDownTime))
        self.bind.fill_whiteMask2Skill = Mathf.Clamp01(1.5 - coolTime / coolDownTime)
        if not self.bPlayedAnim then
          self.bindComponents.skillAnim:Play("anim_battle_skill_cd_white", 1)
          self.bPlayedAnim = true
        end
      end
    end
  end
  if self.bind.go_skillCd ~= go_skillCd then
    self.bind.go_skillCd = go_skillCd
    if not go_skillCd and self.data.coolDownCount <= 0 and self.bInit then
      self.bind.go_skillCanUseEft = false
      self.bind.go_skillCanUseEft = true
    end
  end
  if self.data.coolDownCount > 0 and skill then
    local coolDown = skill.coolDown
    if self.lastChargeCount ~= coolDown.currentChargeCount then
      if self.lastChargeCount ~= nil and coolDown.currentChargeCount > self.lastChargeCount and self.bInit then
        self.bind.go_skillCanUseEft = false
        self.bind.go_skillCanUseEft = true
      end
      if self.lastChargeCount ~= nil and self.bInit then
        if coolDown.currentChargeCount > self.lastChargeCount then
          self.chargeChildAnim[coolDown.currentChargeCount]:Play("anim_battle_skill_charge_ready")
          self.bPlayedAnim = false
        else
          self.chargeChildAnim[self.lastChargeCount]:Play("anim_battle_skill_charge_use")
          self.bPlayedAnim = false
        end
      else
        for i = 1, #self.chargeChildInfo do
          if i > coolDown.currentChargeCount then
            self.chargeChildAnim[i]:Play("anim_battle_skill_charge_init_hide")
          end
        end
      end
      self.lastChargeCount = coolDown.currentChargeCount
    end
  end
  self.bInit = true
end

function this:hide(options)
  self.bind.go_skillCanUseEft = false
end

return this
