local this = class("pageGuideClickTips", G_UIPageBase)
local skipTime = L_Config:getConfig("game", "GUIDE_UI_TEXT_SKIP_TIME")
local typingSpeed = L_Config:getConfig("game", "GUIDE_UI_TEXT_PRINT_TIME")
local headBasePath = "UI/Atlas/HeroM/tex_icon_hero_m_%s.png"
local storyTextTpl = L_GameTpl:getStoryTextTpl()
local starDirection = {
  up = 1,
  down = 2,
  left = 3,
  right = 4,
  headLeft = 5,
  headRight = 6
}
local headDirectionMap = {left = 1, right = 2}
local directDicMap = {
  [1] = "anim_guide_tipin_d_2",
  [2] = "anim_guide_tipin_u_2",
  [3] = "anim_guide_tipin_r_2",
  [4] = "anim_guide_tipin_l_2",
  [5] = "anim_guide_tipin_r_2",
  [6] = "anim_guide_tipin_l_2"
}

function this.bind()
  return {
    tipText = "",
    keyList = {
      moduleName = "pages/Guide/cellKeyCombinedIcon"
    },
    progress_left = 0,
    progress_right = 0,
    progress_up = 0,
    progress_down = 0,
    progress_head_left = 0,
    progress_head_right = 0,
    progressNodeActive_left = false,
    progressNodeActive_right = false,
    progressNodeActive_up = false,
    progressNodeActive_down = false,
    progressNodeActive_head_left = false,
    progressNodeActive_head_right = false,
    checkMarkActive = false,
    timerIconActive = false,
    tipAnchoredPos = C_Vector2(0, 0),
    starNode = true,
    starAcnchoredPos = C_Vector2(0, 0),
    guideClickTipsActive = true,
    canvasGroup_board = 0,
    tab_direction = 1,
    leftHead = "",
    rightHead = "",
    storyBtnActive = false,
    arrowIconActive = false,
    dotIconActive = false
  }
end

function this.methods()
  return {
    onClick_storyNextBtn = function(self)
      if self.isUpdatePos or self.bind.canvasGroup_board == 0 then
        return
      end
      if self.waitClose then
        return
      end
      if not self.options.isDescribeAction or self.isTyping and not self.canSkipTyping then
        return
      end
      if self.isTyping and self.canSkipTyping then
        self.bindComponents.typeWriter:SkipTyping()
        return
      end
      if self.currentStoryIndex >= #self.storyData then
        self.waitClose = true
        self:doClose(function()
          if self.options.finishCallback then
            self.options.finishCallback()
          end
        end)
        return
      end
      self:playNextStory()
    end
  }
end

function this:update()
  if self.isUpdatePos then
    return
  end
  if not self.options or self.bStopLogic then
    return
  end
  local isParentShow = true
  if not L_CommonUtil.isValid(self.options.parentTrans) then
    isParentShow = false
  else
    isParentShow = self.options.parentTrans.gameObject.activeInHierarchy
  end
  if L_GuideManager:checkCurrentAllPages(self.options.validPages) and isParentShow then
    self.bind.canvasGroup_board = 1
  else
    self.bind.canvasGroup_board = 0
  end
end

function this:preOpen(options)
  this.super.preOpen(self, options)
  L_GuideManager:addListener(G_GuideClasses.GuideEvent.GuideClickInputChecked, self.onInputChecked, self)
  L_GuideManager:addListener(G_GuideClasses.GuideEvent.GuideClickPass, self.onGuideClickPass, self)
end

function this:updateTipsPosWithCoordinates()
  local parentTrans = self.options.parentTrans
  if parentTrans == nil then
    return
  end
  if not string.isEmpty(self.options.tipPos) then
    local tipPos = string.split(self.options.tipPos, "|")
    local pos = C_Vector2(tonumber(tipPos[1]), tonumber(tipPos[2]))
    self.bindComponents.tipsRect.anchoredPosition = pos
  end
  if not string.isEmpty(self.options.tipOffset) then
    local offset = string.split(self.options.tipOffset, "|")
    local pos = self.bindComponents.tipsRect.anchoredPosition
    local finalPos = C_Vector2(pos.x + tonumber(offset[1]), pos.y + tonumber(offset[2]))
    self.bindComponents.tipsRect.anchoredPosition = finalPos
  end
end

function this:updateTipsPos()
  if not self.isBind then
    return
  end
  if not L_CommonUtil.isValid(self.options.effectGameobject) then
    return
  end
  local parentTrans = self.options.parentTrans
  if parentTrans == nil then
    return
  end
  local boxSize = self.bindComponents.textBoxRect.sizeDelta
  local tipSize = self.bindComponents.tipsRect.sizeDelta
  local pos = self.options.effectGameobject.transform.position
  local posNew = L_UI:getRoot():InverseTransformPoint(pos)
  if string.isEmpty(self.options.tipPos) and self.options.effectSize ~= nil then
    if self.options.arrowDirection == starDirection.up then
      posNew.y = posNew.y - self.options.effectSize.y / 2 - boxSize.y / 2 - 35
    elseif self.options.arrowDirection == starDirection.down then
      posNew.y = posNew.y + self.options.effectSize.y / 2 + boxSize.y / 2 + 35
    elseif self.options.arrowDirection == starDirection.left then
      posNew.x = posNew.x + self.options.effectSize.x / 2 + boxSize.x / 2 + 25
    elseif self.options.arrowDirection == starDirection.right then
      posNew.x = posNew.x - self.options.effectSize.x / 2 - boxSize.x / 2 - 25
    else
      posNew.y = posNew.y - self.options.effectSize.y / 2 - boxSize.y / 2 - 35
    end
    self.bindComponents.tipsRect.anchoredPosition = C_Vector2(posNew.x, posNew.y)
    self.bindComponents.tipsRect.anchoredPosition = C_Vector2(posNew.x, posNew.y)
  end
  self:updateTipsPosWithCoordinates()
  local starPos = C_Vector2.zero
  local starRotation = C_Vector3.zero
  if self.options.arrowDirection == starDirection.up then
    starPos.y = starPos.y + boxSize.y / 2 - 15
    starRotation.z = -90
  elseif self.options.arrowDirection == starDirection.down then
    starPos.y = starPos.y - boxSize.y / 2 + 15
    starRotation.z = 90
  elseif self.options.arrowDirection == starDirection.left then
    starPos.x = starPos.x - boxSize.x / 2 + 10
    starRotation.z = 0
  elseif self.options.arrowDirection == starDirection.right then
    starPos.x = starPos.x + boxSize.x / 2 - 12
    starRotation.z = 180
  else
    starPos.y = starPos.y + boxSize.y / 2
    starRotation.z = 0
  end
  if not string.isEmpty(self.options.arrowPos) then
    local offset = string.split(self.options.arrowPos, "|")
    starPos.x = starPos.x + tonumber(offset[1])
    starPos.y = starPos.y + tonumber(offset[2])
  end
  self.bind.starAcnchoredPos = C_Vector2(starPos.x, starPos.y)
  self.bindComponents.starRect.localRotation = Unity.Quaternion.Euler(starRotation)
  self.bind.tab_direction = self.options.arrowDirection
  if not self.options.isDescribeAction then
    if self.options.headDirection == headDirectionMap.left then
      self.bind.tab_direction = starDirection.headLeft
    end
    if self.options.headDirection == headDirectionMap.right then
      self.bind.tab_direction = starDirection.headRight
    end
  end
  self.isUpdatePos = false
  self.bind.canvasGroup_board = 1
  self.bindComponents.tipAnimation:Play(directDicMap[self.options.arrowDirection])
end

function this:open(options)
end

function this:close()
  self:disposeVoice()
  self.bindComponents.typeWriter:RemoveCompletedCallback()
  L_GuideManager:removeListener(G_GuideClasses.GuideEvent.GuideClickInputChecked, self.onInputChecked, self)
  L_GuideManager:removeListener(G_GuideClasses.GuideEvent.GuideClickPass, self.onGuideClickPass, self)
  self:disposeSkipTimer()
  self:disposeTween()
  if self.timer then
    Timer.remove(self.timer)
    self.timer = nil
  end
end

function this:disposeVoice()
  if self.curVoice ~= nil then
    L_AudioUtil.stopSound(self.curVoice)
    self.curVoice = nil
  end
end

function this:onGuideClickPass()
  self:doClose()
end

function this:onInputChecked()
  self.bind.checkMarkActive = true
  self.bind.timerIconActive = false
  if L_UI:checkPageOpen(self.pageName) then
    self.bindComponents.tipAnimation:Play("anim_guide_tipcheck")
    self:playEffectAnim()
    self.bStopLogic = true
    if self.timer then
      Timer.remove(self.timer)
      self.timer = nil
    end
    self.timer = Timer.once(0.6, function()
      L_UI:close(self.pageName)
    end, self)
  end
end

function this:show(options)
  self.options = options
  self.bind.arrowIconActive = false
  self.bind.dotIconActive = false
  self:disposeTween()
  self.bind.canvasGroup_board = 0
  self.isUpdatePos = true
  self.waitClose = false
  self:updateUI(options)
  Timer.once(0.033, function()
    self:updateTipsPos()
  end, self, self.gameObject)
  if self.timer then
    Timer.remove(self.timer)
    self.timer = nil
  end
  self.bStopLogic = false
  self.bind.starNode = not self.options.isDescribeAction
end

function this:updateUI(options)
  self.bind.keyList:clear()
  self.bind.storyBtnActive = options.isDescribeAction or false
  self.bindComponents.typeWriter:ResetMaxCharacter()
  if not options.isDescribeAction then
    self:setNormalTips(options)
  else
    self:setStoryTips(options)
  end
  if not string.isEmpty(options.headIcon) then
    self.bind.leftHead = string.format(headBasePath, options.headIcon)
    self.bind.rightHead = string.format(headBasePath, options.headIcon)
  end
  L_GameUtil.forceRebuildLayout(self.bindComponents.tipsRect)
  L_GameUtil.forceRebuildLayout(self.bindComponents.textBoxRect)
end

function this:onTypingEnd()
  self.isTyping = false
  self:refreshStoryArrow()
end

function this:refreshStoryArrow()
  if not self.isBind then
    return
  end
  self.bind.arrowIconActive = self.canSkipTyping or not self.isTyping
  self.bind.dotIconActive = not self.canSkipTyping and self.isTyping
end

function this:setStoryTips(options)
  self:setProgress(false)
  self.bindComponents.typeWriter:SetTypingSpeed(typingSpeed)
  self.typingHandler = self.typingHandler or handler(self, self.onTypingEnd)
  self.bindComponents.typeWriter:SetCompletedCallback(self.typingHandler)
  self.isStoryText = not string.isEmpty(options.storyTextIds)
  if self.isStoryText then
    self.storyData = string.split(options.storyTextIds, "|")
  else
    self.storyData = string.split(options.wordsIds, "|")
  end
  self.currentStoryIndex = 0
  self:playNextStory()
end

function this:disposeSkipTimer()
  if self.skipTimer ~= nil then
    Timer.remove(self.skipTimer)
    self.skipTimer = nil
  end
end

function this:playNextStory()
  self.currentStoryIndex = self.currentStoryIndex + 1
  self.canSkipTyping = false
  self:disposeSkipTimer()
  self.skipTimer = Timer.once(skipTime, function()
    self.canSkipTyping = true
    self:refreshStoryArrow()
  end, self)
  if self.isStoryText then
    if not string.isEmpty(self.storyData[self.currentStoryIndex]) then
      local textId = tonumber(self.storyData[self.currentStoryIndex])
      local tpl = storyTextTpl:getTplById(textId)
      self.bindComponents.typeWriter:StartTyping(storyTextTpl:getDialogDetail(tpl))
      if not string.isEmpty(storyTextTpl:getVoiceEventId(tpl)) then
        self:disposeVoice()
        self.curVoice = L_AudioUtil.playVoiceSound(storyTextTpl:getVoiceEventId(tpl))
      end
      self.isTyping = true
    end
  elseif not string.isEmpty(self.storyData[self.currentStoryIndex]) then
    local wordId = self.storyData[self.currentStoryIndex]
    self.bindComponents.typeWriter:StartTyping(L_WordsTpl:getValue(wordId))
    self.isTyping = true
  end
  self:refreshStoryArrow()
end

function this:setNormalTips(options)
  if not string.isEmpty(options.storyTextId) then
    local textId = tonumber(options.storyTextId)
    local tpl = storyTextTpl:getTplById(textId)
    self.bind.tipText = storyTextTpl:getDialogDetail(tpl)
    if not string.isEmpty(storyTextTpl:getVoiceEventId(tpl)) then
      self:disposeVoice()
      self.curVoice = L_AudioUtil.playVoiceSound(storyTextTpl:getVoiceEventId(tpl))
    end
  else
    self.bind.tipText = options.showTips
  end
  self.bind.checkMarkActive = false
  self.bind.timerIconActive = false
  self.bind.keyList:clear()
  local keyData = {}
  for _, key in ipairs(options.showKeys) do
    if not string.isEmpty(key) then
      table.insert(keyData, {keyText = key, isLongPress = false})
    end
  end
  if not string.isEmpty(options.longPressKey) then
    table.insert(keyData, {
      keyText = options.longPressKey,
      isLongPress = true
    })
  end
  self.bind.keyList:insert_array(keyData)
  if self.options.showTime ~= nil and self.options.showTime > 0 then
    self:setShowTime()
  end
  self:setProgress(not math.isEmpty(self.options.showTime))
end

function this:setShowTime()
  self.progress = 0
  self.bind.checkMarkActive = false
  self.bind.timerIconActive = true
  local getter = function()
    return self.progress
  end
  local setter = function(r)
    self.progress = r
    self:setProgress(true, self.progress)
  end
  self:setProgress(true, self.progress)
  self.tween = DOTween.To(getter, setter, 1, self.options.showTime):SetEase(Tweening.Ease.Linear):OnComplete(function()
    self.bind.timerIconActive = false
    self.bStopLogic = true
    if self.timer then
      Timer.remove(self.timer)
      self.timer = nil
    end
    self:doClose()
    self:disposeTween()
  end)
end

function this:doClose(callback)
  if self.bindComponents.tipAnimation ~= nil then
    self.bindComponents.tipAnimation:Play("anim_guide_tipout")
    printf("guide pageGuideClickTips", "\229\188\186\229\188\149\229\175\188\230\143\144\231\164\186\230\146\173\230\148\190out\229\138\168\231\148\187")
  end
  self:playEffectAnim()
  self.timer = Timer.once(0.167, function()
    printf("guide pageGuideClickTips", "\229\188\186\229\188\149\229\175\188\230\143\144\231\164\186\230\173\163\229\188\143\229\133\179\233\151\173")
    L_UI:close(self.pageName)
    if callback then
      callback()
    end
  end, self)
end

function this:playEffectAnim()
  if L_CommonUtil.isValid(self.options.effectGameobject) then
    local animator = self.options.effectGameobject:GetComponent(typeof(C_CsAnimator))
    if animator ~= nil then
      local aniName = "anim_guide_squareBtn_hide"
      if string.find(self.options.effectGameobject.name, "circle") then
        aniName = "anim_guide_circleBtn_hide"
      end
      animator:Play(aniName, -1, 0)
      printf("guide pageGuideClickTips", aniName)
    end
  end
end

function this:disposeTween()
  if L_CommonUtil.isValid(self.tween) then
    self.tween:Kill()
    self.tween = nil
  end
end

function this:escHandle()
end

function this:setProgress(isActive, progressNum)
  self.bind.progressNodeActive_left = isActive
  self.bind.progressNodeActive_right = isActive
  self.bind.progressNodeActive_up = isActive
  self.bind.progressNodeActive_down = isActive
  self.bind.progressNodeActive_head_left = isActive
  self.bind.progressNodeActive_head_right = isActive
  if isActive and progressNum then
    self.bind.progress_left = 1 - progressNum
    self.bind.progress_right = 1 - progressNum
    self.bind.progress_up = 1 - progressNum
    self.bind.progress_down = 1 - progressNum
    self.bind.progress_head_left = 1 - progressNum
    self.bind.progress_head_right = 1 - progressNum
  end
end

return this
