local this = class("pagePetEvo", G_UIPageBase)
local petInfoTpl = L_GameTpl:getPetTpl()
local petLearningEnumTpl = L_GameTpl:getPetLearingEnumTpl()
local petGradeTpl = L_GameTpl:getPetGradeTpl()
local battleInfoTpl = L_GameTpl:getBattleInfoTpl()
local wordsTpl = L_GameTpl:getWordsTpl()
local petRankTpl = L_GameTpl:getPetRankTpl()
local petRankVoiceTpl = L_GameTpl:getPetRankVoiceTpl()
local _screenPosToUI = Unity.RectTransformUtility.ScreenPointToLocalPointInRectangle

function this:ctor(...)
  this.super.ctor(self, ...)
  self.data = {
    gradeTxtColor = {
      [1] = {
        [1] = "#FFFFFF",
        [2] = "#AFAFAF"
      },
      [2] = {
        [1] = "#FFFFFF",
        [2] = "#AFAFAF"
      },
      [3] = {
        [1] = "#FFFFFF",
        [2] = "#94F0D8"
      },
      [4] = {
        [1] = "#FFFFFF",
        [2] = "#94F0D8"
      },
      [5] = {
        [1] = "#FFFFFF",
        [2] = "#8EB6FF"
      },
      [6] = {
        [1] = "#FFFFFF",
        [2] = "#8EB6FF"
      },
      [7] = {
        [1] = "#FFFFFF",
        [2] = "#C893FF"
      },
      [8] = {
        [1] = "#FFFFFF",
        [2] = "#FFF196",
        [3] = "#FFE08E"
      },
      [9] = {
        [1] = "#FFFFFF",
        [2] = "#FFFAE8",
        [3] = "#FFCBE2",
        [4] = "#FDE8FF",
        [5] = "#EBF5FF"
      }
    },
    frameIncon = {
      [0] = "Page/PetBox/tex_pet_bg_nonebg",
      [1] = "Page/PetBox/tex_pet_bg_firebg",
      [2] = "Page/PetBox/tex_pet_bg_windbg",
      [3] = "Page/PetBox/tex_pet_bg_landbg",
      [4] = "Page/PetBox/tex_pet_bg_woodbg",
      [5] = "Page/PetBox/tex_pet_bg_icebg",
      [6] = "Page/PetBox/tex_pet_bg_waterbg",
      [7] = "Page/PetBox/tex_pet_bg_thunderbg",
      [8] = "Page/PetBox/tex_pet_bg_lightbg",
      [9] = "Page/PetBox/tex_pet_bg_darkbg"
    },
    elementColor = {
      [0] = "#b7dbf0",
      [1] = "#FF6364",
      [2] = "#FFAD6B",
      [3] = "#e1b839",
      [4] = "#82db84",
      [5] = "#a0faf8",
      [6] = "#5fc5ff",
      [7] = "#8088ff",
      [8] = "#fff4ac",
      [9] = "#8e65da"
    },
    normalEvo = {
      [1] = "UI/Atlas/PetEvo/tex_QBJH_jhcgV2.png",
      [2] = "UI/Atlas/PetEvo/tex_QBJH_jhcg_1v2.png"
    },
    ultraEvo = {
      [1] = "UI/Atlas/PetEvo/tex_QBJH_ultimateV2.png",
      [2] = "UI/Atlas/PetEvo/tex_QBJH_ultimate_1v2.png"
    },
    petSpecialSkill = L_GameConstTpl:getValue("PET_SIGNATURESKILLLIST"),
    petNormalSkill = L_GameConstTpl:getValue("PET_SKILLLIST"),
    petBreakSkill = L_GameConstTpl:getValue("PET_BREAKSKILLLIST")
  }
end

function this.bind()
  return {
    show_timelineImage = true,
    show_skilTip = false,
    show_timelineNode = false,
    preName = "",
    evoTxtColor = CS.UnityEngine.Color(1, 1, 1),
    evoName_1 = "",
    evoName_2 = "",
    evoName_3 = "",
    petGradeIcon = "",
    petGradeIconAfter_1 = "",
    petGradeIconAfter_2 = "",
    curGrade = "",
    curGrade_1 = "",
    curGrade_2 = "",
    curGrade_3 = "",
    nextGrade_1 = "",
    nextGrade_2 = "",
    nextGrade_3 = "",
    attrList = {
      moduleName = "pages/Pet/cellTimelineComprehension"
    },
    rideTips = false,
    skillInfo = false,
    skillElement = "",
    skillIcon = "",
    skillName = "",
    skillLv = "",
    skillDesc = "",
    skillGroup = false,
    skillList = {
      moduleName = "pages/Pet/cellPetEvoSkill"
    },
    evoChangeImg = "",
    evoChangeImg_blur = ""
  }
end

function this.methods()
  return {
    onClick_skipTimeline = function(self)
      local index = self.firstPause == false and 1 or 2
      if self.bindComponents.playableDirector.time < 3.8 then
        return
      end
      if self.firstPause == false then
        self.bind.skillInfo = false
        self.bindComponents.playableDirector.time = 4.5333
        self.bindComponents.playableDirector:Resume()
        self.bind.show_skilTip = false
        L_AudioUtil.playSound("Play_SFX_System_UI_Evolve_Rate")
        self.firstPause = true
      else
        self:closeEvolutionTimeline()
      end
    end,
    onAnimation_event = function(self, type)
      if type ~= "grade" then
        return
      end
      self._animationEventJob = co.start(self.animationEventHandle, self)
    end,
    skillList = {
      onClick_Choose = function(self, data, position)
        self:showSkillInfo(data, position)
      end
    }
  }
end

function this:animationEventHandle()
  local endValue = self.nextGrade - math.ceil(self.offset * 0.045)
  co.wait(0.27)
  local getter = function()
    return self.curGrade
  end
  local setter = function(v)
    self.bind.curGrade = L_HeroManager:addComma(math.ceil(v))
    self.bind.curGrade_1 = L_HeroManager:addComma(math.ceil(v))
    self.bind.curGrade_2 = L_HeroManager:addComma(math.ceil(v))
    self.bind.curGrade_3 = L_HeroManager:addComma(math.ceil(v))
  end
  local tween = DOTween.To(getter, setter, endValue, 1.567):SetEase(self.customCurve)
  co.call(tween.OnComplete, tween, co.callback)
  co.wait(0.165)
  self.bind.curGrade = L_HeroManager:addComma(self.nextGrade - math.ceil(self.offset * 0.014))
  self.bind.curGrade_1 = L_HeroManager:addComma(self.nextGrade - math.ceil(self.offset * 0.014))
  self.bind.curGrade_2 = L_HeroManager:addComma(self.nextGrade - math.ceil(self.offset * 0.014))
  self.bind.curGrade_3 = L_HeroManager:addComma(self.nextGrade - math.ceil(self.offset * 0.014))
  co.wait(0.333)
  self.bind.curGrade = L_HeroManager:addComma(self.nextGrade)
  self.bind.curGrade_1 = L_HeroManager:addComma(self.nextGrade)
  self.bind.curGrade_2 = L_HeroManager:addComma(self.nextGrade)
  self.bind.curGrade_3 = L_HeroManager:addComma(self.nextGrade)
end

function this:preOpen(options)
  this.super.preOpen(self, options)
  self.firstPause = false
  self.petId = options.prePetData.id
  self.prePetData = options.prePetData
  self.guid = options.guid
  self.oldSkillInfo = options.oldSkillInfo
  L_SceneManager:setSceneActiveForTimeline(false)
end

function this:open()
  self:initPage()
  self:playEvolutionTimeline(self.petId)
end

function this:show()
  AzurWorld.visbleMgr:SetWeatherActive(true)
end

function this:initPage()
  local guid = self.guid
  local pet = L_PetStore:getPetItem(guid)
  self.data.isSpecial = pet:isSpecialPet()
  self.data.isFlash = pet:hasFlashGene()
  self.skillInfos = L_PetStore:getPetSkills(pet, false, false, true)
  self.customCurve = self.bindComponents.customCurve.curves[0] or Tweening.Ease.OutCirc
  local tpl = petRankTpl:getTplById(self.petId)
  local petTpl = petInfoTpl:getTplById(self.petId)
  local preName = petInfoTpl:getName(petTpl, pet:isSpecialPet())
  local next_id = petRankTpl:getNextPetId(tpl)
  local nextPetTpl = petInfoTpl:getTplById(next_id)
  local nextPetName = petInfoTpl:getName(nextPetTpl, pet:isSpecialPet())
  local stage = petInfoTpl:getPetStage(nextPetTpl)
  local canRide = petInfoTpl:getIsMount(nextPetTpl)
  self.bind.evoChangeImg = stage == L_Const.petStage.ultimate and self.data.ultraEvo[1] or self.data.normalEvo[1]
  self.bind.evoChangeImg_blur = stage == L_Const.petStage.ultimate and self.data.ultraEvo[2] or self.data.normalEvo[2]
  self.bind.rideTips = canRide
  self.bind.preName = preName
  self.bind.evoName_1 = nextPetName .. "\239\188\129"
  self.bind.evoName_2 = nextPetName .. "\239\188\129"
  self.bind.evoName_3 = nextPetName .. "\239\188\129"
  local _, color = C_ColorUtility.TryParseHtmlString(petRankTpl:getEvolutionColor(tpl))
  self.bind.evoTxtColor = color
  self.groupColor = {
    [1] = C_Color.white,
    [2] = color
  }
  self.bindComponents.changeTxtColor.LinearColor1 = self.groupColor[1]
  self.bindComponents.changeTxtColor.LinearColor2 = self.groupColor[2]
  local topRankComprehension = L_PetStore:getRangeValueComprehension(false, 8, pet.comprehension)
  local signalListener = self.bindComponents.skillGroup:GetComponent(typeof(C_TimelineSignalListener))
  if signalListener then
    signalListener:SetHandler(handler(self, self.timelineSignalListener))
  end
  local property = L_PetStore:getPetOriginalProperty(self.prePetData, pet.lv, self.petId)
  local nextProperty = L_PetStore:getPetOriginalProperty(pet, pet.lv, next_id)
  local grade = self.prePetData.grade
  local gradeRank = L_PetStore:calGradeRank(grade)
  local gradeTpl = petGradeTpl:getTplById(gradeRank)
  local curGrade = L_HeroManager:addComma(grade)
  self.bind.curGrade = curGrade
  self.bind.curGrade_1 = curGrade
  self.bind.curGrade_2 = curGrade
  self.bind.curGrade_3 = curGrade
  self.bind.petGradeIcon = petGradeTpl:getIcon(gradeTpl)
  local nextGradeTpl = petGradeTpl:getTplById(nextProperty.gradeRank)
  local nextGrade = L_HeroManager:addComma(nextProperty.grade)
  self.nextGrade = nextProperty.grade
  self.curGrade = grade
  self.offset = self.nextGrade - self.curGrade
  local curGradeGradient = self:parseColor(self.data.gradeTxtColor[nextProperty.gradeRank])
  local nextGradeGradient = self:parseColor(self.data.gradeTxtColor[nextProperty.gradeRank])
  for i = 1, 3 do
    self.bindComponents["txtColor_" .. i].LinearGradient = curGradeGradient
    self.bindComponents["txtColorAfter_" .. i].LinearGradient = nextGradeGradient
  end
  self.bind.petGradeIconAfter_1 = petGradeTpl:getIcon(nextGradeTpl)
  self.bind.petGradeIconAfter_2 = petGradeTpl:getIcon(nextGradeTpl)
  self.bind.nextGrade_1 = nextGrade
  self.bind.nextGrade_2 = nextGrade
  self.bind.nextGrade_3 = nextGrade
  self.bind.attrList:clear()
  local propertyData = {}
  local all_Attribute = petLearningEnumTpl:getAllEnum()
  for i, v in ipairs(all_Attribute) do
    local tpl = petLearningEnumTpl:getTplById(i)
    local enumId = petLearningEnumTpl:getEnumNum(tpl)
    local id = 0
    for n, k in pairs(topRankComprehension) do
      if k.attr_id == enumId then
        id = k.rankId
        break
      end
    end
    local offset = L_PetStore:getPetAttFinalValue(nextProperty, enumId) - L_PetStore:getPetAttFinalValue(property, enumId)
    local battleTpl = battleInfoTpl:getTplById(enumId)
    local isRatio = battleInfoTpl:getIsRatio(battleTpl)
    if isRatio == 1 then
      offset = math.ceil(offset / 100)
    end
    table.insert(propertyData, {
      value = offset,
      isRatio = isRatio,
      attr_icon = petLearningEnumTpl:getIcon(tpl),
      attr_shiningIcon = petLearningEnumTpl:getShiningIcon(tpl),
      name = petLearningEnumTpl:getName(tpl),
      attrId = id,
      curve = self.bindComponents.customCurve.curves[1] or Tweening.Ease.InOutCirc,
      index = i,
      order = petLearningEnumTpl:getOrder(tpl)
    })
  end
  table.sort(propertyData, function(a, b)
    return a.order < b.order
  end)
  self.bind.attrList:insert_array(propertyData)
  self.changeList = {}
  if table.isEmpty(self.skillInfos) then
    for i = 1, 4 do
      table.insert(self.changeList, "")
    end
    self.bind.skillGroup = false
  else
    if #self.skillInfos < #self.oldSkillInfo then
      for i = 1, 4 do
        table.insert(self.changeList, "")
      end
      self.bind.skillGroup = false
      return
    end
    self.bind.skillGroup = true
    self:handleSkillChange()
    local specialSkill
    local normalSkill = {}
    local breakSkill, newBreakSkill
    for _, v in ipairs(self.oldSkillInfo) do
      if v.skillSlot == self.data.petSpecialSkill then
        specialSkill = v
      elseif v.skillSlot >= self.data.petNormalSkill[1] and v.skillSlot <= self.data.petNormalSkill[2] then
        table.insert(normalSkill, v)
      elseif v.skillSlot == self.data.petBreakSkill then
        breakSkill = v
      end
      printf("\232\191\155\229\140\150\229\137\141\230\138\128\232\131\189slot:" .. v.skillSlot .. " \230\138\128\232\131\189ID:" .. v.skillId)
    end
    for _, v in ipairs(self.skillInfos) do
      if v.skillSlot == self.data.petBreakSkill then
        newBreakSkill = v
      end
      printf("\232\191\155\229\140\150\229\144\142\230\138\128\232\131\189slot:" .. v.skillSlot .. " \230\138\128\232\131\189ID:" .. v.skillId)
    end
    local specialPool = petInfoTpl:getSignatureSkillList(petTpl)
    local newSpecialPool = petInfoTpl:getSignatureSkillList(nextPetTpl)
    local oldIndex = 0
    local haveSame = false
    local sameIndex
    if specialSkill ~= nil then
      for i, v in pairs(specialPool) do
        if v[2] == specialSkill.skillId then
          oldIndex = v[1]
        end
      end
      for _, n in ipairs(newSpecialPool) do
        if n[2] == specialSkill.skillId then
          haveSame = true
          sameIndex = n[1]
          break
        end
      end
    end
    local isChange = true
    for i, v in pairs(newSpecialPool) do
      if v[1] == oldIndex then
        isChange = false
        break
      end
    end
    if isChange then
      table.insert(self.changeList, "anim_petup_JN_change")
    elseif haveSame and sameIndex == oldIndex then
      table.insert(self.changeList, "")
    else
      table.insert(self.changeList, "anim_petup_JN_up")
    end
    local skillPool = petInfoTpl:getCommonSkillList(petTpl)
    local newSkillPool = petInfoTpl:getCommonSkillList(nextPetTpl)
    for i, v in ipairs(normalSkill) do
      local index
      local haveSameId = false
      local sameIdIndex
      local change = true
      for _, n in ipairs(newSkillPool) do
        if n[2] == v.skillId then
          haveSameId = true
          sameIdIndex = n[1]
          break
        end
      end
      for _, n in ipairs(skillPool) do
        if n[2] == v.skillId then
          index = n[1]
          break
        end
      end
      for _, n in pairs(newSkillPool) do
        if n[1] == index then
          change = false
          break
        end
      end
      if change then
        table.insert(self.changeList, "Change")
      elseif haveSameId and sameIdIndex == index then
        table.insert(self.changeList, "")
      else
        table.insert(self.changeList, "Up")
      end
    end
    if breakSkill == nil then
      table.insert(self.changeList, "Change")
    elseif breakSkill.skillId == newBreakSkill.skillId then
      table.insert(self.changeList, "")
    else
      table.insert(self.changeList, "Up")
    end
  end
end

function this:escHandle()
  if self.bindComponents.playableDirector.time >= 8 then
    self:closeEvolutionTimeline()
  end
end

function this:close(options)
  this.super.close(self, options)
  if self.timelineControl then
    self.timelineControl:dispose()
    self.timelineControl = nil
  end
  if self._timelineSignalJob then
    co.stop(self._timelineSignalJob)
    self._timelineSignalJob = nil
  end
  if self._animationEventJob then
    co.stop(self._animationEventJob)
    self._animationEventJob = nil
  end
  L_SceneManager:setSceneActiveForTimeline(true)
  AzurWorld.visbleMgr:SetWeatherActive(false)
  L_PetStore:call(L_PetStore.event.setCurPetId, self.guid, true)
end

function this:closeEvolutionTimeline(isForce)
  if self.timelineControl == nil then
    return
  end
  if not isForce and not self.timelineControl:getIsLoop() then
    return
  end
  self.timelineControl:dispose()
  self.timelineControl = nil
  L_AudioUtil.playSound("Play_SFX_System_QiboEvolution_End")
  C_GameAudioManager.PauseBgm(false)
  L_UI:close("pagePetEvo")
  local skillInfoQueue = L_PetStore:getPetSkillInfoQueue()
  local length = skillInfoQueue:getLength()
  for i = 1, length do
    local data = skillInfoQueue:deQueue()
    L_UI:open("pagePetSkillNewInfo", data)
  end
  L_PetStore:setIsPlayingTimeLine(false)
end

function this:playEvolutionTimeline(petId)
  local tpl = petRankTpl:getTplById(petId)
  if tpl == nil then
    return
  end
  local evoPerform = petRankTpl:getEvoPerform(tpl)
  if string.isEmpty(evoPerform) then
    return
  end
  if self.timelineControl == nil then
    self.timelineControl = require("ui.pages.pet.timeline.petTimelineController").new()
  end
  C_GameAudioManager.PauseBgm(true)
  
  function self.timelineControl.loadErrorFunc()
    self:closeEvolutionTimeline(true)
  end
  
  function self.timelineControl.startPlayFunc()
    self.bind.show_timelineImage = false
    local delta = co.wait(2.7)
    self.bindComponents.playableDirector:Play()
    self.bind.show_timelineNode = true
    delta = co.wait(0.2 - delta)
    L_AudioUtil.playSound("Play_SFX_System_UI_Evolve_Transform")
    co.wait(0.6 - delta)
    L_PetStore:playPetVoiceSound(petId, L_PetConst.PetSystemVoiceType.Evolve)
  end
  
  local nextPetId = petRankTpl:getNextPetId(tpl)
  local loopFrame = petRankTpl:getLoopFrame(tpl)
  local tpls = petRankVoiceTpl:getTplsByTimeline(evoPerform)
  if tpls then
    local audioEvents = {}
    for stage, v in pairs(tpls) do
      if type(stage) == "string" then
        audioEvents[stage] = petRankVoiceTpl:getAudioEvent(v)
      end
    end
    self.timelineControl.clipAudioEvents = audioEvents
  end
  local petData = {
    pet1 = petId,
    pet1Rot = petRankTpl:getPet1Rotation(tpl),
    pet1Scale = petRankTpl:getPet1Scale(tpl),
    pet2 = nextPetId,
    pet2Rot = petRankTpl:getPet2Rotation(tpl),
    pet2Scale = petRankTpl:getPet2Scale(tpl),
    isSpecial = self.data.isSpecial,
    isFlash = self.data.isFlash
  }
  self.bind.show_timelineImage = true
  self.timelineControl:playTimelineState(evoPerform, petData, loopFrame)
end

function this:updateTimelineTip()
  local showTip = false
  if self.timelineControl and self.timelineControl:getIsLoop() then
    showTip = true
  end
  self.bind.show_skilTip = showTip
end

function this:parseColor(colorList)
  if #colorList == 0 or #colorList == 1 then
    return
  end
  local gradient
  local list = {}
  for i, v in ipairs(colorList) do
    local _, color = C_ColorUtility.TryParseHtmlString(v)
    table.insert(list, color)
  end
  if #colorList == 2 then
    gradient = C_CustomColorUtility.GenerateGradientLinear(list[1], 1, 0, list[2], 1, 1)
  elseif #colorList == 3 then
    gradient = C_CustomColorUtility.GenerateGradientLinear(list[1], 1, 0, list[2], 1, 0.5, list[3], 1, 1)
  elseif #colorList == 4 then
    gradient = C_CustomColorUtility.GenerateGradientLinear(list[1], 1, 0, list[2], 1, 0.33, list[3], 1, 0.66, list[4], 1, 1)
  elseif #colorList == 5 then
    gradient = C_CustomColorUtility.GenerateGradientLinear(list[1], 1, 0, list[2], 1, 0.25, list[3], 1, 0.5, list[4], 1, 0.75, list[5], 1, 1)
  end
  return gradient
end

function this:showSkillInfo(data, position)
  if self.firstPause == true then
    return
  end
  if self.bind.skillInfo == false then
    self.bind.skillInfo = true
  end
  local info = data.skillInfo
  self.bind.skillElement = self.data.frameIncon[info.skillElement[1]] or self.data.frameIncon[0]
  self.bind.skillIcon = info.itemIcon
  self.bind.skillName = info.skillName
  self.bind.skillLv = info.skillLv
  self.bind.skillDesc = info.describe
  local skillPointPos = position
  local screenPos = C_CameraManager.uiCamera:WorldToScreenPoint(skillPointPos)
  local v2 = C_Vector2(screenPos.x, screenPos.y)
  local rect = self.bindComponents.skillInfoTrans
  local parent = rect.parent
  local _, uiPos = _screenPosToUI(parent, v2, C_CameraManager.uiCamera)
  uiPos.y = uiPos.y + 240
  L_Vector3.setAnchored(rect, uiPos)
  L_GameUtil.forceRebuildLayout(self.bindComponents.descBoard)
end

function this:timelineSignalListener(signalMsg)
  local allIndex = #self.bind.skillList
  self._timelineSignalJob = co.start(function()
    for i = 1, allIndex do
      if signalMsg == "Show" or signalMsg == "Hide" then
        if 1 < i and i == allIndex then
          co.wait(i == allIndex and 0.033 or 0.066, true)
        end
        self.bind.skillList:getItemCls(i):playAnim(signalMsg)
      elseif signalMsg == "Change" then
        if 1 < i then
          co.wait(i == allIndex and 0.066 or 0.1, true)
        end
        self.bind.skillList:getItemCls(i):playAnim(self.changeList[i])
      end
    end
  end)
end

function this:handleSkillChange()
  local skillData = {}
  self.bind.skillList:clear()
  if table.isEmpty(self.oldSkillInfo) then
    for i, v in ipairs(self.skillInfos) do
      local _, color = C_ColorUtility.TryParseHtmlString(self.data.elementColor[v.skillElement[1]] or "#b7dbf0")
      table.insert(skillData, {
        skillBeforeIcon = v.itemIcon,
        skillBeforeColor = color,
        skillAfterIcon = v.itemIcon,
        skillAfterColor = color,
        skillInfo = v,
        linearColor = {
          [1] = self.groupColor[1],
          [2] = self.groupColor[2]
        }
      })
    end
  else
    for i, v in ipairs(self.oldSkillInfo) do
      local _, color = C_ColorUtility.TryParseHtmlString(self.data.elementColor[v.skillElement[1]] or "#b7dbf0")
      skillData[i] = {
        skillBeforeIcon = v.itemIcon,
        skillBeforeColor = color,
        skillInfo = v,
        linearColor = {
          [1] = self.groupColor[1],
          [2] = self.groupColor[2]
        },
        skillAfterIcon = v.itemIcon,
        skillAfterColor = color
      }
    end
    for i, v in ipairs(self.skillInfos) do
      local _, color = C_ColorUtility.TryParseHtmlString(self.data.elementColor[v.skillElement[1]] or "#b7dbf0")
      if skillData[i] then
        skillData[i].skillAfterIcon = v.itemIcon
        skillData[i].skillAfterColor = color
        skillData[i].skillInfo = v
      else
        skillData[i] = {
          skillBeforeIcon = v.itemIcon,
          skillBeforeColor = color,
          skillInfo = v,
          linearColor = {
            [1] = self.groupColor[1],
            [2] = self.groupColor[2]
          },
          skillAfterIcon = v.itemIcon,
          skillAfterColor = color
        }
      end
    end
  end
  self.bind.skillList:insert_array(skillData)
end

return this
