local this = class("modulePhotoGroup_hero", require("ui.pages.photo.group.modulePhotoGroup_base"))
local _screenPosToUI = Unity.RectTransformUtility.ScreenPointToLocalPointInRectangle
local putMax = L_GameClientTpl:getValue("PHOTO_HERO_NUM")

function this.bind()
  return {
    heroList = L_Const.ModuleInfo.CellIconUnit,
    txt_page = "",
    txt_count = "",
    isActive_pageBtn = true,
    isActive_next = true,
    isActive_back = true,
    isActive_drag = false
  }
end

function this.methods()
  return {
    onDrag_heroHandle = function(self, screenPos)
      self:onDragHeroHandle(screenPos)
    end,
    onStartDrag = function(self)
      self.isDragging = true
    end,
    onEndDrag = function(self)
      self.isDragging = false
    end,
    onClick_Put = function(self)
      self:onClickPut()
    end,
    onClick_Recycle = function(self)
      self:onClickRecycle()
    end,
    onClick_cancel = function(self)
      self:onClickCancel()
    end,
    onClick_Next = function(self)
      self:onClickNext()
    end,
    onClick_Back = function(self)
      self:onClickBack()
    end,
    onClick_takeOver = function(self)
      self:onClickTakeOver()
    end
  }
end

function this:open()
  self:create3DUINode()
  self.selectHeroGuid = 0
  self.heroPutInfo = {}
  self:initHeroData()
  self.curPageIndex = 1
  self:initHeroList(1)
  self:refreshPageInfo()
  local main = self:getMainControlEntity()
  L_PhotoManager.moduleGroupHero = self
end

function this:show()
  self.timer = Timer.repeated(0.015, self.update, self)
  self.timer:start()
  self:refreshHeroList()
  self._refreshHeroList = handler(self, self.refreshHeroList)
  L_PhotoManager:addListener(L_PhotoManager.event.photoSwitchHero, self._refreshHeroList)
end

function this:hide()
  self.timer:stop()
  Timer.remove(self.timer)
  self.uiNodeGo:SetActive(false)
  self:clearUnFinishOp()
  L_PhotoManager:removeListener(L_PhotoManager.event.photoSwitchHero, self._refreshHeroList)
end

function this:refresh()
end

function this:close()
  if self.uiNodeGo ~= nil then
    C_GameObject.Destroy(self.uiNodeGo)
    self.uiNodeGo = nil
  end
  self:releaseAllHero()
  L_PhotoManager.moduleGroupHero = nil
end

function this:initHeroData()
  local all = L_HeroStore:getAllHero()
  self.allHero = {}
  self.heroPages = {}
  for i, v in pairs(all) do
    local hero_id = L_HeroStore:getHeroGuid(v)
    local data = {
      itemType = L_Const.resType.hero,
      itemId = L_HeroStore:getHeroConfigId(v),
      guid = hero_id
    }
    table.insert(self.allHero, data)
  end
  table.sort(self.allHero, function(x, y)
    local a = x.guid
    local b = y.guid
    local configA = L_ItemTplManager:getHeroItem(x.itemId)
    local configB = L_ItemTplManager:getHeroItem(y.itemId)
    local priorityOrder = {
      function()
        return configA.quality, configB.quality
      end
    }
    for _, getPriorityValue in ipairs(priorityOrder) do
      local valueA, valueB = getPriorityValue()
      if valueA ~= valueB then
        return valueB < valueA
      end
    end
    return a < b
  end)
  self.minPage = 1
  self.maxPage = 1
  for i = 1, #self.allHero do
    local hero = self.allHero[i]
    local index = math.floor((i - 1) / 12) + 1
    if index > self.maxPage then
      self.maxPage = index
    end
    local list = self.heroPages[index]
    if list == nil then
      list = {}
      self.heroPages[index] = list
    end
    table.insert(list, hero)
  end
end

function this:initHeroList(index)
  self.bind.heroList:clear()
  local list = self.heroPages[index]
  local temp = {}
  for _, v in pairs(list) do
    table.insert(temp, {
      itemType = L_Const.resType.hero,
      itemId = v.itemId,
      guid = v.guid,
      callback = handler(self, self.onSelectHero),
      die = false,
      activeHead = false,
      ignorePet = true
    })
  end
  self.bind.heroList:insert_array(temp)
end

function this:onSelectHero(cell)
  local guid = cell.bind.guid
  if L_PlayerManager:isInMounting() then
    L_FlyMsgManager:showNormalMsg("\229\157\144\233\170\145\231\138\182\230\128\129\228\184\139\230\151\160\230\179\149\232\191\155\232\161\140\232\167\146\232\137\178\230\145\134\230\148\190")
    return
  end
  if self.selectHeroGuid ~= 0 then
    L_FlyMsgManager:showNormalMsgByKey("notice_modulePhotoGroup_hero_01")
    return
  end
  if self.heroPutInfo[guid] ~= nil then
    self:takeOver(guid)
    return
  end
  if self:getPutCount() >= putMax then
    L_FlyMsgManager:showNormalMsgByKey("notice_modulePhotoGroup_hero_03")
    return
  end
  if guid == self:getMainControlEntity().UUID then
    L_FlyMsgManager:showNormalMsgByKey("notice_modulePhotoGroup_hero_02")
    return
  end
  self.heroPutInfo[guid] = {}
  self.selectHeroGuid = guid
  AzurWorld.photoMgr:CreateHero(guid, function(entity)
    self:onLoadHeroEntity(guid, entity)
  end)
  self:refreshHeroList()
end

function this:onLoadHeroEntity(guid, entity)
  if self.gameObject == nil and entity ~= nil then
    AzurWorld.photoMgr:ClearHero(entity)
    return
  end
  if entity == nil then
    self.selectHeroGuid = 0
    self.heroPutInfo[guid] = nil
    return
  end
  if not self.isShow then
    AzurWorld.photoMgr:RecycleHero(guid)
    return
  end
  local info = self.heroPutInfo[guid]
  info.entity = entity
  info.luaEntity = L_PlayerManager:getPlayerUnit():getEntityByCEntityId(entity.data.entityId)
  info.collider = entity.model.gameObject:GetComponent(typeof(CS.UnityEngine.CapsuleCollider))
  self:refreshCurSelectHero(guid)
  self.canPut = self:checkCanPut(guid)
end

function this:refreshHeroList()
  for i, v in pairs(self.modules.heroList) do
    v.bind.go_putMask = false
    for guid, info in pairs(self.heroPutInfo) do
      if v.bind.guid == guid then
        v.bind.go_putMask = true
      end
    end
    if v.bind.guid == self:getMainControlEntity().UUID then
      v.bind.go_putMask = true
    end
  end
  local count = self:getPutCount()
  self.bind.txt_count = string.format("%s/%s", count, putMax)
end

function this:onDragHeroHandle(screenPos)
  if self.curSelectEntity == nil then
    return
  end
  local isWater, hitWater = C_CameraManager.mainCamera:ScreenRaycastByLayers(C_Vector2(screenPos.x, screenPos.y), {"Water"}, 60, false)
  local success, hit = C_CameraManager.mainCamera:ScreenRaycastByLayers(C_Vector2(screenPos.x, screenPos.y), {"Default", "Terrain"}, 60, true)
  local info = self.heroPutInfo[self.selectHeroGuid]
  local setWater = isWater and info and info.collider
  if success and isWater then
    local height = info.collider.height * 0.7
    local sub = hit.point.y - hitWater.point.y
    if sub > -height then
      setWater = false
    end
  end
  if setWater then
    local height = info.collider.height * 0.7
    local isDownTerrain, hitTerrain = C_LuaUtility.RayCast(hitWater.point, C_Vector3.down, height, {"Terrain"}, true)
    if isDownTerrain then
      self.curSelectEntity:getTransform().position = hitTerrain.point + C_Vector3(0, 0.01, 0)
    else
      self.curSelectEntity:getTransform().position = hitWater.point + C_Vector3.down * height
    end
    return
  end
  if success then
    local pos = hit.point + C_Vector3(0, 0.01, 0)
    if hit.normal.y > 0.2 then
      self.curSelectEntity:getTransform().position = pos
    end
  end
end

function this:onClickPut()
  if self.curSelectEntity == nil then
    return
  end
  if self.canPut then
    local info = self.heroPutInfo[self.selectHeroGuid]
    info.pos = self.curSelectEntity:getPosition()
    self:refreshCurSelectHero(nil)
  else
    L_FlyMsgManager:showNormalMsgByKey("notice_modulePhotoGroup_hero_04")
  end
end

function this:onClickRecycle()
  if self.curSelectEntity == nil then
    return
  end
  self.heroPutInfo[self.selectHeroGuid] = nil
  self.curSelectEntity:reset()
  AzurWorld.photoMgr:RecycleHero(self.selectHeroGuid)
  self:refreshCurSelectHero(nil)
  self:refreshHeroList()
end

function this:onClickCancel()
  if self.curSelectEntity == nil then
    return
  end
  local info = self.heroPutInfo[self.selectHeroGuid]
  if info.pos == nil then
    self:onClickRecycle()
    return
  end
  self.curSelectEntity:setPosition(info.pos)
  self:refreshCurSelectHero(nil)
  self:refreshHeroList()
end

function this:onClickTakeOver()
  self:takeOver(self.selectHeroGuid)
end

function this:takeOver(guid)
  if self.heroPutInfo[guid] == nil then
    return
  end
  if self.heroPutInfo[guid].entity == nil then
    return
  end
  local canPut
  if guid == self.selectHeroGuid then
    canPut = self.canPut
  else
    canPut = self:checkCanPut(guid)
  end
  if not canPut then
    L_FlyMsgManager:showNormalMsgByKey("notice_modulePhotoGroup_hero_04")
    return
  end
  local mainEntity = self:getMainControlEntity()
  self.heroPutInfo[mainEntity.UUID] = {
    entity = mainEntity.csEntity,
    luaEntity = mainEntity,
    pos = mainEntity:getPosition(),
    collider = mainEntity.gameObject:GetComponent(typeof(CS.UnityEngine.CapsuleCollider))
  }
  local entity = self.heroPutInfo[guid].luaEntity
  local eid = entity:getCsEntityId()
  AzurWorld.photoMgr:TakeOver(eid)
  L_PhotoManager:setMediatorTarget(entity)
  self.heroPutInfo[guid] = nil
  self:refreshCurSelectHero(nil)
  self:refreshHeroList()
end

function this:clearUnFinishOp()
  if self.curSelectEntity ~= nil then
    local info = self.heroPutInfo[self.selectHeroGuid]
    if info.pos == nil then
      AzurWorld.photoMgr:RecycleHero(self.selectHeroGuid)
      self.heroPutInfo[self.selectHeroGuid] = nil
    else
      self.curSelectEntity:setPosition(info.pos)
    end
  end
  local clear = {}
  for i, v in pairs(self.heroPutInfo) do
    if v.pos == nil then
      table.insert(clear, i)
    end
  end
  for _, v in pairs(clear) do
    self.heroPutInfo[v] = nil
  end
  self:refreshCurSelectHero(nil)
end

function this:checkCanPut(guid)
  if guid == nil or guid == 0 or self.heroPutInfo[guid] == nil or self.heroPutInfo[guid].luaEntity == nil then
    return false
  end
  local entity = self.heroPutInfo[guid].luaEntity
  local result = true
  result = result and (entity.csEntity.characterMovement.isOnGround or entity.csEntity.data.characterControlProperty:IsInWater())
  local info = self.heroPutInfo[guid]
  local capsule = info.collider
  local pos = entity:getPosition() + L_Vector3.new(0, capsule.height / 2, 0)
  local hits = C_Physics.OverlapBox(pos, C_Vector3(capsule.radius, capsule.height, capsule.radius))
  for i = 0, hits.Length - 1 do
    local collider = hits[i]
    if not result then
      break
    end
    if collider.gameObject.layer == 7 and collider.gameObject ~= entity.gameObject then
      result = false
    end
  end
  if result then
    self.posImg.color = C_Color.green
  else
    self.posImg.color = C_Color.red
  end
  return result
end

function this:releaseAllHero()
  AzurWorld.photoMgr:ClearAllHero()
  self.heroPutInfo = {}
end

function this:refreshCurSelectHero(guid)
  if guid == nil then
    self.selectHeroGuid = 0
    self.curSelectEntity = nil
    self.uiNodeGo:SetActive(false)
    self.bind.isActive_drag = false
    return
  end
  self.selectHeroGuid = guid
  self.bind.isActive_drag = true
  local info = self.heroPutInfo[self.selectHeroGuid]
  if info == nil then
    self.curSelectEntity = nil
    return
  end
  self.curSelectEntity = info.luaEntity
  if info.pos ~= nil then
    info.pos = self.curSelectEntity:getPosition()
  end
  self:syncDragBtnPos()
  self:syncPosImg()
end

function this:syncDragBtnPos()
  if self.curSelectEntity == nil then
    return
  end
  local worldPos = self.curSelectEntity:getPosition()
  local screenPos, v2
  if not self.isDragging then
    screenPos = C_CameraManager.mainCamera:WorldToScreenPoint(worldPos)
    v2 = C_Vector2(screenPos.x, screenPos.y)
    local _, pos = _screenPosToUI(self.bindComponents.HeroCtrl.transform.parent, v2, C_CameraManager.uiCamera)
    L_Vector3.setAnchored(self.bindComponents.HeroCtrl, pos)
  end
  local col = self.heroPutInfo[self.selectHeroGuid].collider
  worldPos = L_Vector3.getTemp(worldPos.x, worldPos.y + col.height, worldPos.z)
  screenPos = C_CameraManager.mainCamera:WorldToScreenPoint(worldPos)
  v2 = C_Vector2(screenPos.x, screenPos.y)
  local _, pos = _screenPosToUI(self.bindComponents.rectTakeOver.transform.parent, v2, C_CameraManager.uiCamera)
  L_Vector3.setAnchored(self.bindComponents.rectTakeOver, pos)
end

function this:syncPosImg()
  if self.uiNodeGo == nil or self.curSelectEntity == nil then
    return
  end
  if not self.uiNodeGo.activeSelf then
    self.uiNodeGo:SetActive(true)
  end
  local pos = self.curSelectEntity:getPosition()
  self.uiNodeTrs.position = pos + C_Vector3(0, 0.01, 0)
end

function this:clickSelectHero()
  if not Unity.Input.GetMouseButtonDown(0) then
    return
  end
  if Unity.EventSystems.EventSystem.current:IsPointerOverGameObject() then
    return
  end
  local mousePosition = CS.UnityEngine.Input.mousePosition
  local hits = C_CameraManager.mainCamera:ScreenRaycastAllByLayer(C_Vector2(mousePosition.x, mousePosition.y), {"Character"})
  if hits then
    for i = 0, hits.Length - 1 do
      local hit = hits[i]
      local hitObj = hit.collider.gameObject
      for guid, v in pairs(self.heroPutInfo) do
        if v.entity and v.entity.model.gameObject == hitObj then
          self:refreshCurSelectHero(guid)
          return
        end
      end
    end
  end
end

function this:update()
  self:syncDragBtnPos()
  self:syncPosImg()
  self:clickSelectHero()
  self.canPut = self:checkCanPut(self.selectHeroGuid)
end

function this:create3DUINode()
  if self.uiNodeGo ~= nil then
    return
  end
  local go = L_ResPool:syncGameObject("UI/Pages/Photo/petPos3D.prefab", C_LuaUtility.GetRootNode())
  self.uiNodeGo = go
  self.uiNodeTrs = go.transform
  self.posImg = self.uiNodeTrs:Find("petPos"):GetComponent(typeof(C_LImage))
  go:SetActive(false)
  local width = 30
  L_Vector3.setUISize(self.posImg.transform, L_Vector3.getTemp(width, width))
end

function this:onClickNext()
  self.curPageIndex = self.curPageIndex + 1
  self:initHeroList(self.curPageIndex)
  self:refreshPageInfo()
end

function this:onClickBack()
  self.curPageIndex = self.curPageIndex - 1
  self:initHeroList(self.curPageIndex)
  self:refreshPageInfo()
end

function this:refreshPageInfo()
  if self.minPage >= self.maxPage then
    self.bind.isActive_pageBtn = false
  else
    self.bind.isActive_pageBtn = true
    self.bind.txt_page = string.format("%d/%d", self.curPageIndex, self.maxPage)
    self.bind.isActive_next = self.curPageIndex ~= self.maxPage
    self.bind.isActive_back = self.curPageIndex ~= self.minPage
  end
  self:refreshHeroList()
end

function this:getPutCount()
  local count = 1
  for i, v in pairs(self.heroPutInfo) do
    count = count + 1
  end
  return count
end

function this:getMainControlEntity()
  local mainEntity = L_PhotoManager:getMediator().target
  return mainEntity
end

function this:clearPutHeroes()
  for i, v in pairs(self.heroPutInfo) do
    AzurWorld.photoMgr:RecycleHero(i)
  end
  self.heroPutInfo = {}
end

return this
