local this = class("modulePetHabitatMap", G_UIModuleBase)
local _worldFilter = L_GameTpl:getWorldFilterTpl()
local _worldPointTpl = L_GameTpl:getWorldBorthposTpl()
local _worldAreaTpl = L_GameTpl:getWorldAreaTpl()
local _worldMapTpl = L_GameTpl:getWorldMapTpl()
local _areaTpl = L_GameTpl:getAreaTpl()
local _exploreTpl = L_GameTpl:getExploreTpl()
local _exploreLevelTpl = L_GameTpl:getExploreLevelTpl()
local _worldFilterMarkTpl = L_GameTpl:getWorldFilterMarkTpl()
local _screenPosToUI = Unity.RectTransformUtility.ScreenPointToLocalPointInRectangle
local screenOffset = 100

function this.bind()
  return {sliderValue = 0}
end

function this.methods()
  return {
    onClick_add = function(self)
      local value = math.clamp(self.mapData.sliderValue + 0.01, 0, 1)
      self.bindComponents.slider_scale.value = value
    end,
    onClick_decrease = function(self)
      local value = math.clamp(self.mapData.sliderValue - 0.01, 0, 1)
      self.bindComponents.slider_scale.value = value
    end,
    onValueChanged_mapScale = function(self, value)
      self.mapScale = value
      self:setMapScale(self.mapScale)
    end
  }
end

function this:open()
  L_SceneStore:listenCallFunc(L_SceneStore.event.refreshPoint, self.onEvent_refreshTransferNode, self)
  self:configTouch("+")
  self.mapScale = 0
  self.pool = L_PoolManager:getResPool()
  self.timers = {}
  self.mapData = nil
  self.mapBuilder = nil
  self.nodeDic = {}
  self.areaBlockDic = {
    areaBlock = {},
    miniAreaBlock = {},
    sceneBorderTransfer = {},
    areaMask = {},
    areaBoundary = {}
  }
  if L_DeviceTpl:getIsPc() then
    self.updateHandle = handler(self, self.update)
    C_UpdateSource.AddUpdateEventHandler(self.updateHandle, "modulePetCatalogMap.modulePetHabitatMap.update")
  end
end

function this:update()
  local scrollInput = Unity.Input.GetAxis("Mouse ScrollWheel")
  if scrollInput ~= 0 then
    self:updateScroll(scrollInput)
  end
end

function this:updateScroll(dv)
  self.mapScale = self.mapScale + (0 < dv and 0.05 or dv < 0 and -0.05 or 0)
  self.mapScale = math.clamp(self.mapScale, 0, 1)
  self.bindComponents.slider_scale.value = self.mapScale
end

function this:setAreaId(areaId)
  if math.isEmpty(areaId) then
    errorf("\229\156\176\229\155\190areaId\228\184\141\232\131\189\228\184\186\231\169\186")
    return
  end
  if areaId ~= self.curAreaId then
    self:initMap(areaId)
  end
  self.curAreaId = areaId
  self:initCenterPos()
end

function this:close()
  L_SceneStore:unListenCallFunc(L_SceneStore.event.refreshPoint, self.onEvent_refreshTransferNode)
  if L_DeviceTpl:getIsPc() then
    C_UpdateSource.RemoveUpdateEventHandler(self.updateHandle)
  end
  self:configTouch("-")
  L_TimerManager:clearTimer(self)
  self:clearAllTimer()
  self:clearAllNode()
  self.pool:dispose()
end

function this:onEvent_refreshTransferNode()
  self:refreshAllNodeLockState(L_MapConst.mapSievingType.transfer)
end

function this:clearAllTimer()
  for _, v in pairs(self.timers) do
    Timer.remove(v)
  end
  self.timers = {}
  if self.doTweenMap then
    self.doTweenMap:Kill()
  end
end

function this:initMap(areaId)
  self:initMapData(areaId)
  self.mapBuilder = L_MapManager:createMapBuilder(self.mapData)
  self.mapBuilder:paint(self.bindComponents.imgMap)
  local tpl = _worldAreaTpl:getTplById(self.mapData.areaId)
  local isCut = _worldAreaTpl:getIsCut(tpl)
  if self.mapData.isStream and isCut then
    self.mapBuilder:setTargetTrans(self.bindComponents.mapShowRect)
  end
  self:setMapInit(areaId)
  self:clearAllStaticNode()
  self.areaBlockDic.areaBlock = L_MapManager:getMapAreaBlockList(self.mapData.sceneId, self.areaBlockDic.areaBlock)
  self.areaBlockDic.miniAreaBlock = L_MapManager:getMiniAreaBlockList(self.mapData.sceneId, self.areaBlockDic.miniAreaBlock)
  self.areaBlockDic.sceneBorderTransfer = L_MapManager:getAllSceneBorderTransferNode(self.mapData.sceneId, self.areaBlockDic.sceneBorderTransfer)
  self.areaBlockDic.areaMask = L_MapManager:getMapAreaMask(self.mapData.sceneId, self.areaBlockDic.areaMask)
  self.areaBlockDic.areaBoundary = L_MapManager:getMapAreaBoundary(self.mapData.areaId, self.areaBlockDic.areaBoundary)
  if table.isEmpty(self.areaBlockDic.areaMask) then
    self.bindComponents.mapMaskNode.gameObject:ActiveTrans(false)
  else
    self.bindComponents.mapMaskNode.gameObject:ActiveTrans(true)
  end
  for i, list in pairs(self.areaBlockDic) do
    for _, v in ipairs(list) do
      if v.type == L_MapConst.mapSievingType.areaMask or v.type == L_MapConst.mapSievingType.areaBoundary then
        v:generate(self.bindComponents.mapMaskNode.transform, self.pool)
      else
        v:generate(self.bindComponents.entityNode.transform, self.pool)
      end
    end
  end
  self:refreshAllNodeLockState()
  self:refreshAllNodeState()
  self:refreshAllNodePos()
end

function this:setPetConfigId(petConfigId, isNight)
  self.petConfigId = petConfigId
  self:initAllMapNode(petConfigId, isNight)
end

function this:initMapData(areaId)
  local tpl = _worldAreaTpl:getTplById(areaId)
  local curAreaId = areaId
  if string.isEmpty(_worldAreaTpl:getAreaMap(tpl)) then
    local sceneId = _worldAreaTpl:getSceneId(tpl)
    local list = {}
    for i, v in pairs(_worldAreaTpl:getAllArea(sceneId)) do
      table.insert(list, v)
    end
    table.sort(list, function(a, b)
      return _worldAreaTpl:getId(a) < _worldAreaTpl:getId(b)
    end)
    curAreaId = _worldAreaTpl:getId(list[1])
  end
  if self.mapBuilder ~= nil and self.mapBuilder.data.areaId ~= areaId then
    self.mapBuilder:removePaint()
    self.mapBuilder = nil
  end
  self.mapData = L_MapManager:createMapData(curAreaId)
  self.mapData.isStream = true
  self.bind.mapDirection = C_Vector3(0, 0, -self.mapData.mapDirection)
  local rect = self.bindComponents.mapShowRect.rect
  self.mapData:setShowSize(rect.width / 2, rect.height / 2)
  L_Vector3.setSize(self.bindComponents.imgMap, self.mapData.imgScale)
  L_Vector3.setAnchored(self.bindComponents.imgMap, L_Vector3.zero)
end

function this:setMapInit(areaId)
  local tpl = _worldAreaTpl:getTplById(self.mapData.areaId)
  if tpl then
    self.mapScale = L_GameConstTpl:getValue("MAP_ENTER_SCALE") or 0
    self.mapData:checkResolutionRatio()
    self:setMapScale(self.mapScale)
    self.bind.sliderValue = self.mapScale
  end
  local truetpl = _worldAreaTpl:getTplById(areaId)
  if truetpl then
    local sceneId = _worldAreaTpl:getSceneId(truetpl)
    local id = _worldAreaTpl:getId(truetpl)
    local areaData = _areaTpl:getConfig()
    for i, v in ipairs(areaData) do
      if _areaTpl:getWorldAreaId(v) == id and _areaTpl:getSceneId(v) == sceneId then
        self.txtTitle = _areaTpl:getAreaName(v)
        return
      end
    end
    self.txtTitle = _worldAreaTpl:getName(truetpl)
  end
end

function this:setMapPosition(deltaPos)
  if self.bMovingAnim then
    return
  end
  local imgPos = L_Vector3.getAnchored(self.bindComponents.imgMap)
  imgPos.x = imgPos.x + deltaPos.x
  imgPos.y = imgPos.y + deltaPos.y
  imgPos = self.mapData:clampImgPos(imgPos)
  L_Vector3.setAnchored(self.bindComponents.imgMap, imgPos)
  self:refreshAllNodePos()
end

function this:setMapScale(value)
  self.mapData:setSlider(value)
  self.mapBuilder.painter:onSlider(self.mapData.imgScale)
  self.bind.value_sliderScale = value
  local ratio = self.mapData.maxScale / self.mapData.minScale
  local size = L_Vector3.getSize(self.bindComponents.imgMap)
  local pos = L_GameUtil.spToLpInRectangle(self.bindComponents.imgMap, self.mapData.showSize)
  local offset = pos * (size - self.mapData.imgScale)
  L_Vector3.setSize(self.bindComponents.imgMap.transform, self.mapData.imgScale)
  self:setMapPosition(offset)
  for nodeType, list in pairs(self.nodeDic) do
    if nodeType == L_MapConst.mapSievingType.kiboHabitat then
      for _, node in pairs(list) do
        node:refreshScope(value, ratio)
      end
    end
  end
end

function this:initAllMapNode(petConfigId, isNight)
  self:clearAllNode()
  self.nodeDic = L_MapManager:getPetCatalogMapNodeDic(self.mapData.sceneId, petConfigId, isNight or false)
  for nodeType, list in pairs(self.nodeDic) do
    for _, v in ipairs(list) do
      v.mapAreaName = self.txtTitle
      if L_MapManager:checkIsNoMaskNode(nodeType) then
        v:generate(self.bindComponents.noMaskNode.transform, self.pool)
      else
        v:generate(self.bindComponents.entityNode.transform, self.pool)
      end
      v:addClick(function()
      end)
      if nodeType == L_MapConst.mapSievingType.kiboHabitat then
        local value = self.mapScale
        local ratio = self.mapData.maxScale / self.mapData.minScale
        v:refreshScope(value, ratio)
      end
    end
  end
  self:refreshAllNodeLockState()
  self:refreshAllNodeState()
  self:refreshAllNodePos()
end

function this:getNodeList(nodeType)
  return self.nodeDic[nodeType]
end

function this:clearAllNode()
  if table.isEmpty(self.nodeDic) then
    return
  end
  for nodeType, v in pairs(self.nodeDic) do
    self:clearNode(nodeType)
  end
end

function this:clearAllStaticNode()
  if table.isEmpty(self.areaBlockDic) then
    return
  end
  for _, list in pairs(self.areaBlockDic) do
    for _, v in pairs(list) do
      v:onDestroy()
    end
  end
  self.areaBlockDic = {
    areaBlock = {},
    miniAreaBlock = {},
    sceneBorderTransfer = {},
    areaMask = {},
    areaBoundary = {}
  }
end

function this:clearNode(nodeType)
  local list = self.nodeDic[nodeType]
  if list then
    for _, v in ipairs(list) do
      v:onDestroy()
    end
    self.nodeDic[nodeType] = {}
  end
end

function this:refreshAllNodeLockState(mapType)
  if mapType then
    local transferList = self:getNodeList(mapType)
    for _, v in ipairs(transferList) do
      v:refreshLockState()
    end
    if mapType == L_MapConst.mapSievingType.transfer then
      for i, node in ipairs(self.areaBlockDic.areaMask) do
        node:refreshLockState()
      end
    end
  else
    for _, v in pairs(self.nodeDic) do
      for _, node in pairs(v) do
        node:refreshLockState()
      end
    end
    for i, node in ipairs(self.areaBlockDic.areaMask) do
      node:refreshLockState()
    end
  end
end

function this:refreshAllNodeState()
  for _, v in pairs(self.nodeDic) do
    for _, node in pairs(v) do
      node:refreshState(self.mapData)
    end
  end
  for _, list in pairs(self.areaBlockDic) do
    for _, node in pairs(list) do
      node:refreshState(self.mapData)
    end
  end
end

function this:refreshAllNodePos()
  for _, v in pairs(self.nodeDic) do
    for _, node in pairs(v) do
      node:refreshPosByMapData(self.mapData)
      node:refreshState(self.mapData)
    end
  end
  for _, list in pairs(self.areaBlockDic) do
    for _, node in pairs(list) do
      node:refreshPosByMapData(self.mapData)
      node:refreshState(self.mapData)
    end
  end
end

function this:refreshNodeTraceState()
  for _, v in pairs(self.nodeDic) do
    for _, node in pairs(v) do
      node:refreshNodeTraceState()
    end
  end
end

function this:initCenterPos()
  self.bindComponents.imgMap.anchoredPosition = C_Vector2(0, 0)
end

function this:configTouch(operator)
  self.onUIDragStartHandle = self.onUIDragStartHandle or L_CommonUtil.handle(self.onUI_dragStartHandle, self)
  self.onUIDragHandle = self.onUIDragHandle or L_CommonUtil.handle(self.onUI_dragHandle, self)
  self.onUIDragEndHandle = self.onUIDragEndHandle or L_CommonUtil.handle(self.onUI_dragEndHandle, self)
  self.onClickHandle = self.onClickHandle or L_CommonUtil.handle(self.on_clickHandle, self)
  C_ScreenTouch.OnUI_DragStart(operator, self.onUIDragStartHandle)
  C_ScreenTouch.OnUI_Drag(operator, self.onUIDragHandle)
  C_ScreenTouch.OnUI_DragEnd(operator, self.onUIDragEndHandle)
  C_ScreenTouch.OnUI_Click(operator, self.onClickHandle)
end

function this:onUI_dragStartHandle(gesture)
  if not L_CommonUtil.isValid(gesture.go) then
    return
  end
  if gesture.go ~= self.bindComponents.imgMap.gameObject and gesture.go:GetComponent(typeof(C_LMaskImage)) == nil then
    self.isDragInMapPos = false
    return
  end
  self.isDragInMapPos = true
end

function this:onUI_dragHandle(gesture)
  if not L_CommonUtil.isValid(gesture.go) then
    return
  end
  if gesture.go ~= self.bindComponents.imgMap.gameObject and gesture.go:GetComponent(typeof(C_LMaskImage)) == nil then
    if self.dragClickPos ~= nil then
      self.dragClickPos = nil
    end
    self.isDragInMapPos = false
    return
  end
  if self.isDragInMapPos ~= true then
    return
  end
  local pos = gesture.deltaPosition
  self:setMapPosition(pos)
end

function this:onUI_dragEndHandle(gesture)
  if not L_CommonUtil.isValid(gesture.go) then
    return
  end
  if gesture.go ~= self.bindComponents.imgMap.gameObject and gesture.go:GetComponent(typeof(C_LMaskImage)) == nil then
    return
  end
end

function this:on_clickHandle(gesture)
  if gesture.go ~= self.bindComponents.imgMap.gameObject then
    return
  end
end

function this:onUI_pinchIn(gesture)
  self:refreshAllNodePos()
end

function this:onUI_pinchOut(gesture)
  self:refreshAllNodePos()
end

function this:onUI_pinch(gesture)
  self:refreshAllNodePos()
end

return this
