local this = class("pagePhoto", G_UIPageBase)
local _heroTpl = L_GameTpl:getHeroTpl()
local _MovieTimeLimit = L_GameTpl:getGameConstTpl():getValue("PHOTO_MOVIE_TIME", true)
local _PhotographParamTpl = L_GameTpl:getPhotographParamTpl()
local _gameClientTpl = L_GameTpl:getGameClientTpl()
local cameraPreset = _gameClientTpl:getValue("PHOTO_CAMERA_SNAPSHOT")
local cameraPresetName = {
  [1] = "notice_pagePhoto_07",
  [2] = "notice_pagePhoto_08",
  [3] = "notice_pagePhoto_09"
}

function this.bind()
  return {
    goCloseHide = false,
    goFuncPanel = true,
    goGrid = false,
    goCaptureArea = false,
    goWhiteCut = false,
    goBtnMenu = true,
    goRecorder = false,
    goRetarget = false,
    txtRecord = "",
    txtCamPreset = "",
    top = {
      moduleName = "modulePages/moduleCommonTop"
    },
    menu = {
      moduleName = "pages/photo/modulePhotoMenu"
    },
    bev = {
      moduleName = "pages/photo/modulePhotoBev"
    },
    listHeroHeads = {
      moduleName = "modulePages/cellHeroHeadItemCircle"
    },
    activeListHeroHeads = false,
    activeBtnChangeHero = true,
    changeHeroBtnImg = "",
    activeTogList = true,
    activeTogTakeMode = true,
    activeRightMask = true
  }
end

function this.methods()
  return {
    onValueChanged_ui = function(self, isOn)
      self.mediator.isUI = false
    end,
    onValueChanged_viewLine = function(self, isOn)
      local mediator = L_PhotoManager:getMediator()
      local isActive = mediator:getSettingOrDefault(L_Const.photoParam.player)
      if isActive then
        self.mediator.isViewLine = not self.mediator.isViewLine
      else
        L_FlyMsgManager:showNormalMsgByKey("notice_pagePhoto_06")
      end
    end,
    onValueChanged_grid = function(self, isOn)
      self.mediator.isGrid = not self.mediator.isGrid
    end,
    onClick_closeHide = function(self)
      self.mediator.isUI = true
    end,
    onClick_menu = function(self)
      self.mediator.isMenu = true
    end,
    onValueChanged_takeMode = function(self, isOn)
      self.mediator.takeMode = isOn and L_Const.photoTakeMode.normal or L_Const.photoTakeMode.street
    end,
    onClick_retarget = function(self)
    end,
    onClick_reset = function(self)
      self.modules.bev:resetScreen()
    end,
    bev = {
      onClick_capture = this.capture,
      onClick_recording = this.recording
    },
    onClick_changeHero = function(self)
      self:onClickChangeHeroBtn()
    end,
    listHeroHeads = {
      onClick = function(self, bind)
        self:onClickHeroHead(bind)
      end
    },
    onClick_changeCam = function(self)
      self:onClickSwitchCameraPreset()
    end
  }
end

function this:check(options, callback)
  if L_BattleDataManager:checkPlayerBattle() then
    L_FlyMsgManager:showNormalMsg(L_BattleDataManager:getBattleBlockTips(L_Const.BattleBlockType.PhotographEntrance))
    callback(false)
    return
  end
  if L_PlayerManager:inKiBoTransformMainControl() then
    L_FlyMsgManager:showNormalMsgByKey("notice_pagePhoto_05")
    callback(false)
    return
  end
  local isPhotoTask = options and options.isPhotoTask
  local result = isPhotoTask or L_SystemUnlockManager:checkAndTip(L_SystemConst.enum.photo)
  if result then
    result = not L_BattleStore:getIsInBattle() and L_PlayerManager:getMainControlIsFree() and not L_PlayerStore:getIsNewPlayer()
    if not result then
      L_FlyMsgManager:showNormalMsgByKey("notice_pagePhoto_04")
    end
  end
  if result then
    self:fadeIn()
  end
  callback(result)
end

function this:escHandle()
  if self.modules.menu.state == 1 then
    if self.mediator.isMenu then
      self.mediator.isMenu = false
      return
    else
      L_GameUtil.showCommonTip({
        txtContent = L_WordsTpl:getValue("notice_pagePhoto_03"),
        confirmCallback = function()
          L_UI:close(self.pageName)
        end
      })
    end
  elseif self.modules.menu.state == 2 then
    self.modules.menu:translateState(1)
    return
  end
end

function this:preOpen(options)
  self.isPhotoTask = options and options.isPhotoTask or false
  L_PhotoManager:sendEvent(L_PhotoManager.event.pagePhotoOpen)
  self.mediator = L_PhotoManager:enterPhoto()
  local entity = options and options.entity or L_PlayerManager:getMainHeroEntity()
  AzurWorld.photoMgr.isPhotoTask = self.isPhotoTask
  AzurWorld.photoMgr:CreatePlayerUnitAdapter()
  AzurWorld.playerMgr.myPlayerUnitAdapter.pause = true
  C_GameTime.ActiveUITimeAgent()
  C_GameTime.SetTimeOfDayTickFactor(0)
  L_CameraManager:switchToPhoto()
  L_PlayerManager:stopIdleAnim()
  L_PhotoManager:addListener(L_PhotoManager.event.selectPhotoHeroChange, self.onEvent_selectPhotoHeroChange, self)
  L_ShortCutManager:addListener(L_ShortCutConst.event.Mount, self.onEvent_ShortCutMount, self)
  L_ShortCutManager:addListener(L_ShortCutConst.event.MountFly, self.onEvent_ShortCutMountFly, self)
  L_PhotoManager:registerCreateHeroFunc(handler(self, self.switchPhotoHero))
  local isMount = L_PlayerManager:isInMounting()
  if isMount then
    L_PhotoManager:setMediatorTarget(entity)
    if not self.isPhotoTask then
      L_CameraManager:refreshVirCameraOffset(entity)
    end
  else
    local mainHeroEntity = L_PlayerManager:getMainControlEntity()
    L_PhotoManager:setMediatorTarget(mainHeroEntity)
    if not self.isPhotoTask then
      L_CameraManager:refreshVirCameraOffset(mainHeroEntity)
    end
  end
  self.mediator.photoFilter = self.bindComponents.photoFilter
  self.mediator.volume = self.bindComponents.volume
  self.updateHeadBoardHandle = L_CommonUtil.handle(self.updateHeadBoard, self)
  self.cameraPresetIndex = 2
  self.cameraPresetIndexMark = -1
  self:switchCameraPreset(self.cameraPresetIndex)
  self:initTop()
  self:injectMediator()
  self:initZoom()
  self:initHeroList()
  self:bindScreenTouch("+")
  local wind = C_RealWeather.GetWeatherWind()
  if wind then
    wind:SetMagicaDirectionalWind(self.bindComponents.magicWind)
  end
  AzurWorld.HomeMgr:LockAllEffect(true)
  if not self.isPhotoTask and not isMount then
    AzurWorld.photoMgr:SwitchHero(entity.UUID, function(e)
      local mainHeroEntity = L_PlayerManager:getMainControlEntity()
      L_PhotoManager:setMediatorTarget(mainHeroEntity)
      L_CameraManager:refreshVirCameraOffset(mainHeroEntity)
    end)
  end
  if self.isPhotoTask then
    self:onPhotoTask()
    L_CameraManager:setVirCameraScaleView(true)
    local page = C_UIMgr.GetPage(self.pageName)
    if page then
      page.overrideInputMap = C_InputManager_MapType.PagePhotoTask
    end
  end
  L_PhotoManager.useHighResolution = self.mediator:getSettingOrDefault(L_Const.photoParam.highResolution)
end

function this:close()
  C_GameTime.SetTimeOfDayTickFactor(1)
  C_GameTime.InactiveUITimeAgent()
  AzurWorld.HomeMgr:LockAllEffect(false)
  self:shutdownHeadBoard()
  self:bindScreenTouch("-")
  self.mediator:revertSetting()
  if AzurWorld.playerMgr.myPlayerUnitAdapter ~= nil then
    AzurWorld.playerMgr.myPlayerUnitAdapter.pause = false
  end
  AzurWorld.photoMgr:DisposePlayerUnitAdapter()
  if AzurWorld.playerMgr.myPlayerUnitAdapter ~= nil then
    AzurWorld.playerMgr.myPlayerUnitAdapter:ResumePlayerUnit(nil, true)
  end
  L_PhotoManager:setMediatorTarget()
  L_PhotoManager:exitPhoto()
  L_CameraManager:revertCamController()
  L_PlayerManager:initIdleAnim()
  L_PhotoManager:removeListener(L_PhotoManager.event.selectPhotoHeroChange, self.onEvent_selectPhotoHeroChange, self)
  L_ShortCutManager:removeListener(L_ShortCutConst.event.Mount, self.onEvent_ShortCutMount, self)
  L_ShortCutManager:removeListener(L_ShortCutConst.event.MountFly, self.onEvent_ShortCutMountFly, self)
  if self.isRecording then
    self:cancelRecord()
  end
  local wind = C_RealWeather.GetWeatherWind()
  if wind then
    wind:SetMagicaDirectionalWind(nil)
  end
  if self.expressionCtrl then
    self.expressionCtrl:destroy()
  end
  L_PhotoManager:releaseHead(self)
  if self.isPhotoTask then
  end
end

function this:show()
  self.isWaitingCapture = false
end

function this:hide()
  if self.isRecording then
    self:cancelRecord()
  end
end

function this:fadeIn()
  local data = {
    coverdTime = 0.9,
    fadeOut = true,
    fadeIn = false,
    isCompleteClose = true
  }
  L_GameUtil.openMask(data)
end

function this:initTop()
  local data = {
    name = L_WordsTpl:getValue("notice_pagePhoto_02"),
    mainBtn = false,
    closeCurPage = function()
      L_UI:close(self.pageName)
    end,
    mainBtn = function()
      L_UI:close(self.pageName)
    end
  }
  self.modules.top:initModule(data)
end

function this:initZoom()
  local fixFollow = L_CameraManager:getFixedFollow()
  if fixFollow then
    local fix = function(isVolume)
      local target = self.mediator.target
      self.faceIn = isVolume
      if target then
        local ik = target:getLookAtIKComponent(true)
        if isVolume then
          ik:tryEnableIK(L_CameraManager:getSceneCameraTransform())
        elseif not self.mediator.isViewLine then
          ik:disableIK()
        end
      end
      local cameraController = L_CameraManager:getCurCamController()
      if not isVolume then
        cameraController:resetDistanceLimit()
      end
    end
    
    function fixFollow.zoomInAction()
      fix(true)
    end
    
    function fixFollow.zoomOutAction()
      fix(false)
    end
  end
end

function this:bindScreenTouch(sign)
  self.onDragStartHandle = self.onDragStartHandle or L_CommonUtil.handle(self.onTouch_dragStart, self)
  self.onDragHandle = self.onDragHandle or L_CommonUtil.handle(self.onTouch_drag, self)
  self.onDragEndHandle = self.onDragEndHandle or L_CommonUtil.handle(self.onTouch_dragEnd, self)
  C_ScreenTouch.OnUI_DragStart(sign, self.onDragStartHandle)
  C_ScreenTouch.OnUI_Drag(sign, self.onDragHandle)
  C_ScreenTouch.OnUI_DragEnd(sign, self.onDragEndHandle)
end

function this:onTouch_dragStart(gesture)
  self.touchViewHold = gesture.go == self.bindComponents.viewHold.gameObject
  if self.touchViewHold then
    self:startHeadBoard()
  end
end

function this:onTouch_drag(gesture)
  if not self.touchViewHold then
    return
  end
  local ikComponent = self.mediator.target:getLookAtIKComponent()
  if ikComponent then
    local parent = self.bindComponents.viewHold.parent
    local width = parent.rect.width * 0.48
    local height = parent.rect.height * 0.48
    local temp = L_GameUtil.spToLpInRectangle(parent, gesture.position)
    temp.x = math.clamp(temp.x, -width, width)
    temp.y = math.clamp(temp.y, -height, height)
    L_Vector3.setAnchored(self.bindComponents.viewHold, temp)
    self:ikReadViewHold(ikComponent)
  end
end

function this:onTouch_dragEnd()
  if self.touchViewHold then
    self:startHideHeadBoard()
  end
  self.touchViewHold = nil
end

function this:startHeadBoard()
  self:shutdownHeadBoard()
  self.bindComponents.headBoard.gameObject:ActiveTrans(true)
  self:refreshHeadBoard()
end

function this:startHideHeadBoard()
  if self.headTimer then
    return
  end
  self.headTimer = Timer.once(3, function()
    self.bindComponents.headBoard.gameObject:ActiveTrans(false)
    self.headTimer = nil
  end, nil, self.gameObject)
end

function this:updateHeadBoard()
  local target = self.mediator.target
  if target and target:getGameObject().activeSelf then
    local headBoard = self.bindComponents.headBoard
    if headBoard.gameObject.activeSelf then
      self:refreshHeadBoard()
    end
  else
    self:shutdownHeadBoard()
  end
end

function this:shutdownHeadBoard()
  if self.headTimer == nil then
    return
  end
  self.bindComponents.headBoard.gameObject:ActiveTrans(false)
  Timer.remove(self.headTimer)
  self.headTimer = nil
end

function this:refreshHeadBoard()
  local headBoard = self.bindComponents.headBoard
  local target = self.mediator.target
  if target then
    local headCenter = target:getLookAtIKComponent():getHeadCenter()
    local camera = L_CameraManager:getSceneCamera()
    local view = camera:WorldToScreenPoint(headCenter)
    local pos = L_Vector3.screenToLocalInRectangle(headBoard.parent, view)
    L_Vector3.setAnchored(headBoard, pos)
    local dis = L_CameraManager:getCameraDis()
    local fov = 60 / L_CameraManager:getFov()
    dis = dis / fov
    local size = 0
    if 1 <= dis then
      size = 50 + 300 / (dis * dis)
    else
      size = 50 + 300 / dis
    end
    L_Vector3.setUISize(headBoard, L_Vector3.getTemp(size, size))
  end
end

function this:injectMediator()
  local calls = {
    target = handler(self, self.translateTarget),
    isUI = handler(self, self.translateUI),
    isViewLine = handler(self, self.translateIK),
    bevMode = handler(self, self.translateBevMode),
    takeMode = handler(self, self.translateTakeMode),
    isMenu = handler(self, self.translateMenu),
    playFaceActionId = handler(self, self.translateFaceActionId)
  }
  local bevMediator = self.modules.bev:getMediators()
  self.mediator:addHandlers(calls)
  self.mediator:addHandlers(bevMediator)
  L_PhotoManager.util:injectMediator_setting()
  self.mediator:invokeAll()
  L_PhotoManager:createCurWorldData()
end

function this:translateMenu(isShow, old)
  self.bind.goBtnMenu = not isShow
  self.modules.menu.gameObject:ActiveTrans(isShow)
end

function this:translateGrid(isShow)
  self.bind.goGrid = isShow
end

function this:translateTarget(entity, oldEntity, isQuick)
  if oldEntity then
    self:translateIK(false, false, oldEntity)
    if oldEntity.modelControl then
      local grounderIK = oldEntity.modelControl:GetComponentByType(typeof(C_GrounderIK))
      if grounderIK then
        grounderIK.OnPostIK = nil
      else
        local ik = oldEntity:getLookAtIKComponent()
        if ik then
          ik:removePostUpdate(self.updateHeadBoardHandle)
        end
      end
    end
    if oldEntity.csEntity and not oldEntity.csEntity.data.active then
      oldEntity:reset()
    end
  end
  if entity then
    local grounderIK = entity.modelControl:GetComponentByType(typeof(C_GrounderIK))
    if grounderIK then
      grounderIK.OnPostIK = self.updateHeadBoardHandle
    else
      local ik = entity:getLookAtIKComponent()
      if ik then
        ik:addPostUpdate(self.updateHeadBoardHandle)
      end
    end
    L_CameraManager:bindEntity(entity, isQuick)
    L_PhotoManager:sendEvent(L_PhotoManager.event.selectPhotoHeroChange, entity:getGuid())
    self:translateIK(self.mediator.isViewLine, false, entity)
    if self.expressionCtrl then
      self.expressionCtrl:setTarget(entity)
    end
  end
end

function this:translateUI(isShow, old)
  self.bind.goCloseHide = not isShow
  self.bind.goFuncPanel = isShow
end

function this:translateIK(isIK, old, entity)
  self.bindComponents.viewHold.gameObject:ActiveTrans(isIK)
  entity = entity or self.mediator.target
  if entity then
    local lookAt = entity:getLookAtIKComponent(true)
    if isIK then
      local point = self:ikReadViewHold(lookAt)
      lookAt:enableIK(point)
    elseif self.faceIn then
      lookAt:enableIK(L_CameraManager:getSceneCameraTransform())
    else
      lookAt:disableIK()
    end
  end
end

function this:ikReadViewHold(ik)
  local point = ik:getForwardIKPoint()
  local pos = L_Vector3.getAnchored(self.bindComponents.viewHold)
  local camera = L_CameraManager:getSceneCamera()
  local transTarget = self.mediator.target:getTransform()
  local dis = camera.transform:Distance(transTarget)
  pos = pos / 250
  local transHead = ik:getHead()
  local height = transHead:Distance(transTarget)
  local forwardCam = camera.transform.forward
  local forwardPlayer = transTarget.forward
  forwardCam.y = 0
  forwardPlayer.y = 0
  local angle = C_Vector3.Angle(forwardCam, forwardPlayer)
  local sign = angle < 90 and 1 or -1
  L_Vector3.setLocalPos(point, L_Vector3.getTemp(sign * pos.x, height + pos.y, dis))
  return point
end

function this:translateBevMode(mode)
  local isRecord = mode == L_Const.photoBevMode.recording
  if not isRecord and self.isRecording then
    self:cancelRecord()
  end
end

function this:translateTakeMode(mode)
  self.bind.goRetarget = mode == L_Const.photoTakeMode.street
end

function this:capture()
  self.bind.goWhiteCut = true
  self.bind.goCaptureArea = true
  L_PhotoManager:capture(function(t2d)
    L_UI:open("pagePhotoPreview", {
      rt = t2d,
      isPhotoTask = self.isPhotoTask
    }, function()
      self.bind.goWhiteCut = false
      self.bind.captureArea = false
    end)
    local sceneId = AzurWorldInstance.CurWorldId
    local worldAreaId = L_AreaStore:getMapAreaId()
    L_AchievementStore:req_clientBehaviourRecord(L_Const.commonCondition.RegionPhotoTimes, {
      sceneId,
      worldAreaId,
      1
    }, function()
      printf("req_clientBehaviourRecord", sceneId, worldAreaId)
    end)
  end, nil, nil, true)
end

function this:recording()
  if not self.isRecording then
    if self.isWaitingCapture then
      return
    end
    self.bindComponents.movieCapture.gameObject:SetActive(true)
    Timer.once(0, function()
      local res = self.bindComponents.movieCapture:StartCapture(handler(self, self.onRecordCompleted))
      if not res then
        return
      end
      self.isRecording = true
      self.bind.goRecorder = true
      self.isWaitingCapture = true
      self.recordSecond = 0
      self:refreshRecording()
      self.recordTimer = Timer.repeated(0, function()
        self.recordSecond = self.recordSecond + Unity.Time.deltaTime
        if self.recordSecond >= _MovieTimeLimit then
          Timer.remove(self.recordTimer)
          self.recordTimer = nil
          if self.isRecording then
            self:recording()
          end
        else
          self:refreshRecording()
        end
      end)
    end)
  else
    if self.recordSecond < 0.5 then
      return
    end
    if self.recordTimer then
      Timer.remove(self.recordTimer)
      self.recordTimer = nil
    end
    self.isRecording = false
    self.bind.goRecorder = false
    self.bindComponents.movieCapture:StopCapture()
  end
end

function this:refreshRecording()
  self.bind.txtRecord = string.format("%02d:%02d", math.floor(self.recordSecond / 60), math.floor(self.recordSecond % 60))
end

function this:cancelRecord()
  if self.recordTimer then
    Timer.remove(self.recordTimer)
    self.recordTimer = nil
  end
  self.isRecording = false
  self.bind.goRecorder = false
  self.bindComponents.movieCapture:CancelCapture()
end

function this:onRecordCompleted(res, path)
  if res then
    L_UI:open("pagePhotoPreview", {moviePath = path})
  else
    self.isWaitingCapture = false
  end
end

function this:translateFaceActionId(actionId)
  if not self.mediator.target or not actionId then
    return
  end
  if not self.expressionCtrl then
    self.expressionCtrl = require("ui.pages.photo.photoExpressionController").new()
    self.expressionCtrl:setTarget(self.mediator.target)
  end
  if actionId == L_Const.photoParam.defaultFace then
    self.expressionCtrl:stop()
  else
    local tpl = _PhotographParamTpl:getTplById(actionId)
    local param = _PhotographParamTpl:getParam(tpl)
    local animNames = string.split(param, "|")
    local index = 0
    
    local function nextAnim()
      if index < #animNames then
        index = index + 1
        self.expressionCtrl:play(animNames[index], false, nextAnim)
      end
    end
    
    nextAnim()
  end
end

function this:onEvent_ShortCutMount()
  if not L_SystemUnlockStore:getSystemIsOpen(L_SystemConst.enum.mount) then
    return
  end
  local mountId = L_MountStore:getEquipMountId()
  if not mountId or mountId < 1 then
  end
  if AzurWorld.photoMgr.unitAdapter:IsMountMainControl() then
    AzurWorld.photoMgr.unitAdapter:SwitchOutMountMainControl()
  else
    if not C_MountUtil.CheckSceneCanMount() then
      return
    end
    AzurWorld.photoMgr.unitAdapter:SwitchToMountMainControl()
  end
end

function this:onEvent_ShortCutMountFly()
  local status = L_Const.WorldMapPlayerMountStatusType.WMPMST_FLY
  if status == L_PlayerStore:getMountStatus() then
    return
  end
  if not L_PlayerManager:isInMounting() then
    return
  end
  if not AzurWorld.mountMgr:CheckCanChangeMountStatus(C_WorldMapPlayerMountStatusType.WmpmstFly) then
    return
  end
  if not C_MountUtil.CheckCanMountSwitchToStatus(mountGuid, C_WorldMapPlayerMountStatusType.WmpmstFly) then
    return
  end
  AzurWorld.photoMgr.mountStatus = C_WorldMapPlayerMountStatusType.WmpmstFly
  AzurWorld.photoMgr.unitAdapter:SwitchMountMainControlStatus()
end

function this:initHeroList()
  if self.modeController == nil then
    self.modeController = require("ui.pages.HeroPanel.controller.heroListModeController").new()
  end
  self.heroGuidList = self:getAllHeroList()
  self._heroId2FormationData = self:getFormationData()
  self:sortHeroGuidList()
  if AzurWorld.photoMgr.unitAdapter:IsFormationControl() then
    self.modeController:setSelectGuid(L_FormationStore:getControl(L_FormationConst.FormationType.world), true)
  else
    self.modeController:setSelectGuid(L_HeroStore:getDefaultHeroGuid(), true)
  end
  self.heroIndex = self:getHeroIndex()
  self.initHeroId = self:getHeroId()
  self:refreshChangeHeroBtn(self.initHeroId)
  self:populateHeroList()
  self.bind.activeListHeroHeads = false
end

function this:switchPhotoHero(heroId, callback)
  if not AzurWorld.photoMgr.unitAdapter:IsSandTableControl() then
    return
  end
  if not L_PhotoManager:checkCanSwitchHero(heroId) then
    L_FlyMsgManager:showNormalMsgByKey("notice_pagePhoto_01")
    return
  end
  AzurWorld.photoMgr:SwitchHero(heroId, function(entity)
    local mainHeroEntity = L_PlayerManager:getMainControlEntity()
    L_PhotoManager:setMediatorTarget(mainHeroEntity)
    if callback then
      callback(mainHeroEntity)
    end
    L_PhotoManager:sendEvent(L_PhotoManager.event.photoSwitchHero)
  end)
end

function this:getHeroIndex()
  for i, v in ipairs(self.heroGuidList or table.empty) do
    if self.modeController:getSelectGuid() == v then
      return i
    end
  end
  return 1
end

function this:getHeroId()
  local heroId = L_PhotoManager.cacheTempHeroId
  return heroId or self.heroGuidList[self.heroIndex]
end

function this:getFormationData()
  local formationType = L_FormationConst.FormationType.world
  local posData = L_FormationStore:getFormationPosData(formationType)
  local data = {}
  for i, guid in pairs(posData) do
    if not math.isEmpty(guid) then
      data[guid] = i
    end
  end
  return data
end

function this:getAllHeroList()
  local list = {}
  for i, v in pairs(L_HeroStore:getAllHero()) do
    table.insert(list, L_HeroStore:getHeroGuid(v))
  end
  return list
end

function this:sortHeroGuidList()
  table.sort(self.heroGuidList, function(a, b)
    local heroDataA = self.modeController:getHero(a)
    local heroDataB = self.modeController:getHero(b)
    if heroDataA == nil or heroDataB == nil then
      return a < b
    end
    local configA = L_ItemTplManager:getHeroItem(L_HeroStore:getHeroConfigId(heroDataA))
    local configB = L_ItemTplManager:getHeroItem(L_HeroStore:getHeroConfigId(heroDataB))
    local isOutA = self._heroId2FormationData[a] or math.huge
    local isOutB = self._heroId2FormationData[b] or math.huge
    if isOutA ~= isOutB then
      return isOutA < isOutB
    end
    local priorityOrder = {
      function()
        return L_HeroStore:getHeroLevel(heroDataA), L_HeroStore:getHeroLevel(heroDataB)
      end,
      function()
        return configA.quality, configB.quality
      end,
      function()
        return L_HeroStore:getHeroStar(heroDataA), L_HeroStore:getHeroStar(heroDataB)
      end
    }
    for _, getPriorityValue in ipairs(priorityOrder) do
      local valueA, valueB = getPriorityValue()
      if valueA ~= valueB then
        return valueB < valueA
      end
    end
    return a < b
  end)
end

function this:populateHeroList()
  local tempData = {}
  local formationData = self:getFormationData()
  for k, v in ipairs(self.heroGuidList) do
    local heroId = v
    local hero = self.modeController:getHero(heroId)
    local heroConfigId = L_HeroStore:getHeroConfigId(hero)
    local heroHeadAvatarTexture = L_GameUtil.getAvatarTexturePath(heroConfigId, L_Const.resourceIndexOfAvatarTextureInHeroTpl.small)
    local tpl = _heroTpl:getTplById(heroConfigId)
    local elementId = _heroTpl:getElement(tpl)
    local elementTypeTpl = L_GameTpl:getElementTypeTpl()
    local bgIconPath = elementTypeTpl:getProfessionColor(elementTypeTpl:getTplById(elementId), L_Const.professionColorType.circle)
    self.bind.professionBg = bgIconPath
    local professionTpl = L_GameTpl:getProfessionTpl()
    local professionIcon = professionTpl:getIcon(professionTpl:getTplById(_heroTpl:getPosition(tpl)))
    local rarity = _heroTpl:getRarity(tpl)
    local rarityTpl = L_RarityTpl:getTplById(rarity)
    local colorCfg = L_RarityTpl:getColorCircle(rarityTpl)
    for id, _ in pairs(formationData) do
      if id == heroId then
        colorCfg = "#eaffaa"
      end
    end
    local _, color = C_ColorUtility.TryParseHtmlString(colorCfg)
    table.insert(tempData, {
      id = heroId,
      imgHead = heroHeadAvatarTexture,
      txtLevel = "",
      imgCarrer = professionIcon,
      carrerBg = bgIconPath,
      selected = k == self.heroIndex,
      qualityColor = color,
      isPhotoHead = true
    })
  end
  self.bind.listHeroHeads:clear()
  self.bind.listHeroHeads:insert_array(tempData)
  if self.heroIndex then
    self.bindComponents.panelHeroHeads:FocusItemIndex(self.heroIndex - 1)
  end
end

function this:onClickHeroHead(bind)
  L_PhotoManager.cacheTempHeroId = nil
  self:switchPhotoHero(bind.id, function()
    if self.modeController:getSelectGuid() == bind.id then
      return
    end
    self.modeController:setSelectGuid(bind.id)
  end)
end

function this:onClickChangeHeroBtn()
  local isShow = not self.bind.activeListHeroHeads
  self.bind.activeListHeroHeads = isShow
end

function this:refreshHeroHead(newHeroID, oldHeroID)
  if not self.modeController then
    return
  end
  for k, v in ipairs(self.heroGuidList) do
    local heroId = v
    local heroData = self.modeController:getHero(heroId)
    local heroItem = L_ItemManager:parseHeroItem(L_HeroStore:getHeroConfigId(heroData))
    local heroHeadAvatarTexture = L_GameUtil.getAvatarTexturePath(L_HeroStore:getHeroConfigId(heroData), L_Const.resourceIndexOfAvatarTextureInHeroTpl.small)
    self.bind.listHeroHeads:change(k, {
      id = heroId,
      imgHead = heroHeadAvatarTexture,
      txtLevel = "",
      colorCircle = heroItem.qualityColor,
      selected = heroId == newHeroID
    })
  end
end

function this:refreshChangeHeroBtn(heroID)
  heroID = heroID or self:getHeroId()
  if heroID == L_HeroStore:getDefaultHeroGuid() then
    L_PhotoManager:fillMainHead(self, self.bindComponents.changeHeroBtnTrs.gameObject, nil, L_Const.avatarTextureIndex.head)
  else
    L_PhotoManager:releaseHead(self)
    local heroData = self.modeController:getHero(heroID)
    local heroItem = L_ItemManager:parseHeroItem(L_HeroStore:getHeroConfigId(heroData))
    if heroItem then
      local heroHeadAvatarTexture = L_GameUtil.getAvatarTexturePath(L_HeroStore:getHeroConfigId(heroData), L_Const.resourceIndexOfAvatarTextureInHeroTpl.small)
      self.bind.changeHeroBtnImg = heroHeadAvatarTexture
    end
  end
end

function this:onEvent_selectPhotoHeroChange(heroID)
  if not self.isBind or not self.modeController then
    return
  end
  self.modeController:setSelectGuid(heroID, true)
  self.heroIndex = self:getHeroIndex()
  self:refreshHeroHead(heroID)
  self:refreshChangeHeroBtn(heroID)
end

function this:update()
end

function this:onClickSwitchCameraPreset()
  if self.cameraPresetIndex >= 3 then
    self.cameraPresetIndexMark = -1
  elseif self.cameraPresetIndex <= 1 then
    self.cameraPresetIndexMark = 1
  end
  self.cameraPresetIndex = self.cameraPresetIndex + self.cameraPresetIndexMark
  self:switchCameraPreset(self.cameraPresetIndex)
end

function this:switchCameraPreset(index)
  if index <= 0 or index > #cameraPreset then
    return
  end
  local dis = cameraPreset[index]
  local fixFollow = L_CameraManager:getFixedFollow()
  local cameraController = L_CameraManager:getCurCamController()
  if fixFollow then
    if index == 3 then
      L_CameraManager:getCurCamController():setCameraDistance(dis)
      if C_CameraManager.isNeedShowFace then
        fixFollow:ZoomInWithTarget()
      end
    else
      fixFollow:ZoomOutWithTarget()
      cameraController.cameraTactics:StopBehavior(CS.Lens.Gameplay.Modules.BigWorld.CameraBehaviorComponent.BehaviorEnum.EDis)
      cameraController:resetDistanceLimit()
      L_CameraManager:getCurCamController():setCameraDistance(dis)
    end
  end
  self.bind.txtCamPreset = L_WordsTpl:getValue(cameraPresetName[index])
end

function this:onPhotoTask()
  self.bind.goBtnMenu = false
  self.bind.activeTogList = false
  self.bind.activeTogTakeMode = false
  self.bind.activeRightMask = false
end

return this
