local this = class("taskManager", G_EventManagerBase)
table.merge(this, require("ui.manager.task.taskManager_control"))
local _managerTag = "[Task Manager]"
local _taskTpl = L_GameTpl:getTaskTpl()
local _taskTargetTpl = L_GameTpl:getTaskTargetTpl()
local _taskStepTpl = L_GameTpl:getTaskStepTpl()
local _worldMapTpl = L_GameTpl:getWorldMapTpl()
local _worldCityTpl = L_GameTpl:getWorldCityTpl()

function this:toInitCSharpEvent()
  if self._init then
    return
  end
  self._init = true
  self.callBackList = {}
  self.paramFuncList = {}
  self.conditionDic = {}
  self.conditionNPCCount = {}
  L_PlayerManager:addListener(L_PlayerManager.event.setMainControl, self.onEventTaskManagerSendEnd, self)
  L_SceneManager:addListener(L_SceneManager.event.transmitSceneEnd, self.onEventTaskManagerSendEnd, self)
  L_SceneManager:addListener(L_SceneManager.event.switchSceneEnd, self.onEventTaskManagerSendEnd, self)
  L_BattleManager:addListener(L_BattleManager.event.exitBattle, self.onEventTaskManagerSendEnd, self)
  L_PlayerStore:listenCallFunc(L_PlayerStore.event.refreshBaseInfo, self.onEventTaskManagerSendEnd, self)
  self.onEventFlowEnd = handler(self, self.onEventTaskManagerSendEnd)
  C_GameFlow.flowEvent:Listen(C_EGameFlowEvent.FlowOver, self.onEventFlowEnd)
  L_UI:addListener(L_UI.pageEvent.closed, self.onEventClosedPage, self)
  L_UI:addListener(L_UI.pageEvent.hided, self.onEventClosedPage, self)
  L_PhotoManager:addListener(L_PhotoManager.event.photoCaptureFinish, self.onEvent_photographFinish, self)
  L_TaskStore:listenCallFunc(L_TaskStore.event.setCurrentTracedTask, self.onEventTaskAllExecuteOver, self)
  self.onEventTaskAllExecuteOverFunc = handler(self, self.onEventTaskAllExecuteOver)
  self.onEventSetMainControl = nil
  AzurWorld.TaskMgr:RegisterEvent(C_ETaskEvent.TaskAllExecuteOver, self.onEventTaskAllExecuteOverFunc)
  AzurWorld.TaskMgr:RegisterEvent(C_ETaskEvent.TaskServerTaskDeleteSync, self.onEventTaskAllExecuteOverFunc)
end

function this:unLoadToCsharp()
  if not self._init then
    return
  end
  self._init = false
  self.callBackList = {}
  self.paramFuncList = {}
  self.taskSubData = {}
  C_TaskManager.ClearAllTaskTraceInfos()
  self.timer = nil
  L_PlayerManager:removeListener(L_PlayerManager.event.setMainControl, self.onEventTaskManagerSendEnd, self)
  L_SceneManager:removeListener(L_SceneManager.event.transmitSceneEnd, self.onEventTaskManagerSendEnd, self)
  L_SceneManager:removeListener(L_SceneManager.event.switchSceneEnd, self.onEventTaskManagerSendEnd, self)
  L_BattleManager:removeListener(L_BattleManager.event.exitBattle, self.onEventTaskManagerSendEnd, self)
  L_PlayerStore:unListenCallFunc(L_PlayerStore.event.refreshBaseInfo, self.onEventTaskManagerSendEnd, self)
  if self.onEventFlowEnd then
    C_GameFlow.flowEvent:Cancel(C_EGameFlowEvent.FlowOver, self.onEventFlowEnd)
  end
  L_UI:removeListener(L_UI.pageEvent.hided, self.onEventClosedPage, self)
  L_UI:removeListener(L_UI.pageEvent.closed, self.onEventClosedPage, self)
  L_PhotoManager:removeListener(L_PhotoManager.event.photoCaptureFinish, self.onEvent_photographFinish, self)
  L_TaskStore:unListenCallFunc(L_TaskStore.event.setCurrentTracedTask, self.onEventTaskAllExecuteOver, self)
  if self.onEventTaskAllExecuteOverFunc then
    AzurWorld.TaskMgr:UnregisterEvent(C_ETaskEvent.TaskAllExecuteOver, self.onEventTaskAllExecuteOverFunc)
    AzurWorld.TaskMgr:UnregisterEvent(C_ETaskEvent.TaskServerTaskDeleteSync, self.onEventTaskAllExecuteOverFunc)
    self.onEventTaskAllExecuteOverFunc = nil
  end
  if self.onEventSetMainControl then
    L_PlayerManager:removeListener(L_PlayerManager.event.setMainControl, self.onEventSetMainControl, self)
    self.onEventSetMainControl = nil
  end
end

function this:registerCallBack(registerId, callBack)
  if self.paramFuncList == nil then
    return
  end
  self.callBackList[registerId] = callBack
  if L_BattleStore:getIsInBattle() then
    self:onEventTaskAllExecuteOver()
    return
  end
  if C_GameFlow.inLoading then
    return
  end
  if L_PlayerManager:getMainControlEntity() == nil then
    return
  end
  if callBack ~= nil then
    callBack(false)
    self.callBackList[registerId] = nil
  end
end

function this:toCallRegisterFunc()
  if table.isEmpty(self.callBackList) then
    return
  end
  for i, n in pairs(self.callBackList) do
    self.callBackList[i] = nil
    n()
  end
end

function this:toCallEvent()
  if self.keepCallBack ~= nil then
    self.keepCallBack()
  end
end

function this:registerEventCallBack(callBack)
  self.keepCallBack = callBack
end

function this:unregisterCallBack(registerId)
  if self.callBackList == nil then
    return
  end
  if self.callBackList[registerId] == nil then
    return
  end
  self.callBackList[registerId] = nil
end

function this:registerParamCallBack(registerId, callBack)
  if self.paramFuncList == nil then
    return
  end
  self.paramFuncList[registerId] = callBack
end

function this:unregisterParamCallBack(registerId)
  if self.paramFuncList == nil then
    return
  end
  if self.paramFuncList[registerId] == nil then
    return
  end
  self.paramFuncList[registerId] = nil
end

function this:onEventTaskManagerSendEnd()
  local mainPlayer = L_PlayerManager:getMainControlEntity()
  if L_BattleStore:getIsInBattle() then
    return
  end
  if C_GameFlow.inLoading then
    return
  end
  if mainPlayer == nil then
    return
  end
  self:toCallEvent()
  self:toCallRegisterFunc()
end

function this:onEventClosedPage(pageName)
  local list = C_VarList:Get()
  list:AddString(pageName)
  C_WorldEvent.instance:Dispatch(C_EWorldEvent.OnInteractPageClose, list)
  if table.isEmpty(self.paramFuncList) then
    return
  end
  for i, n in pairs(self.paramFuncList) do
    n(pageName)
  end
  if self.hidePage ~= nil then
    self.hidePage(pageName)
    self.hidePage = nil
  end
end

function this:openTaskPhotoPage(insetData, oriPos, targetPos, callBack)
  local targetEntityId = insetData.targetNpcId
  local targetRange = insetData.targetRange
  local npcId = insetData.npcId
  local isSuccess = false
  local isPhotoFinish = false
  local oriPosition = C_Vector3(oriPos.x, oriPos.y, oriPos.z)
  local targetPosition = C_Vector3(targetPos.x, targetPos.y, targetPos.z)
  L_UI:open("pagePhoto", {isPhotoTask = true})
  if targetEntityId ~= 0 or targetRange ~= 0 then
    L_UI:open("pagePhotographScene", {
      callback = function(tempOver)
        isSuccess = tempOver
        if isPhotoFinish == true then
          print("[\230\139\141\231\133\167\229\137\167\230\131\133Log] Lua isSuccess true")
        end
      end,
      targetEntityId = targetEntityId,
      targetRange = targetRange,
      npcId = npcId,
      oriPos = oriPosition,
      targetPos = targetPosition
    })
  end
  
  function self.photographFinish()
    if isSuccess then
      print("[\230\139\141\231\133\167\229\137\167\230\131\133Log] Lua photographFinish CallBack Success")
      isPhotoFinish = true
      callBack(isPhotoFinish)
      L_UI:close("pagePhoto")
      self.photographFinish = nil
    end
  end
  
  function self.onEvent_hidePage(pageName)
    if pageName == "pagePhoto" then
      callBack(isPhotoFinish)
      if L_UI:getPage("pagePhotographScene") ~= nil then
        L_UI:close("pagePhotographScene")
      end
    end
  end
end

function this:removePhotographFinis()
  self.photographFinish = nil
end

function this:onEvent_photographFinish()
  print("[\230\139\141\231\133\167\229\137\167\230\131\133Log] Lua onEvent_photographFinish")
  if L_UI:checkPageOpen("pagePhotographScene") and self.photographFinish ~= nil then
    print("[\230\139\141\231\133\167\229\137\167\230\131\133Log] Lua photographFinish CallBack")
    self.photographFinish()
  end
end

function this:transmitSceneEnd(sceneId)
  if self.transmitCallBack ~= nil then
    self.transmitCallBack()
  end
  L_SceneManager:removeListener(L_SceneManager.event.switchSceneEnd, self.transmitSceneEnd, self)
  L_SceneManager:removeListener(L_SceneManager.event.transmitSceneEnd, self.transmitSceneEnd, self)
  L_SceneManager:removeListener(L_SceneManager.event.loadSceneEnd, self.transmitSceneEnd, self)
end

function this:onEventTaskAllExecuteOver()
  C_TaskManager.RefreshTaskTraceInfo()
  L_TaskStore:call(L_TaskStore.event.refreshTask)
end

function this:getCurTaskIdsByTabType(tabType)
  local res = {}
  local ids = C_TaskManager.GetTaskExecuteTaskId()
  for i = 0, ids.Count - 1 do
    local tplTask = _taskTpl:getTplById(ids[i])
    if _taskTpl:getTabType(tplTask) == tabType then
      table.insert(res, ids[i])
    end
  end
  return res
end

function this:getTaskType(taskId)
  local tplTask = _taskTpl:getTplById(taskId)
  return tplTask and _taskTpl:getType(tplTask)
end

function this:getTaskTabType(taskId)
  local tplTask = _taskTpl:getTplById(taskId)
  return tplTask and _taskTpl:getTabType(tplTask)
end

function this:GetNodeInfoParam(taskId, nodeId)
  return C_TaskManager.GetNodeInfoParam(taskId, nodeId)
end

function this:GetNodeInfoParamByIndex(taskId, nodeId, index)
  local res, data = C_TaskManager.TryGetNodeInfoParam(taskId, nodeId, index)
  if res then
    return data
  end
end

function this:getTaskAllNodeIdList(taskId)
  local nodeIds = C_TaskManager.GetTaskAllShowNodeIdList(taskId)
  local res = {}
  for i = 0, nodeIds.Count - 1 do
    res[i + 1] = nodeIds[i]
  end
  return res
end

function this:getHashFinishNode(taskId)
  local res = {}
  local ids = C_TaskManager.GetTaskFinishNodeIdList(taskId)
  for i = 0, ids.Count - 1 do
    res[ids[i]] = ids[i]
  end
  return res
end

function this:GetTaskStepId(taskId, taskNodeId)
  return C_TaskManager.GetTaskStepId(taskId, taskNodeId)
end

function this:IsTaskInLimitStep(taskId)
  local nodeId = C_TaskManager.GetExcuteNode(taskId)
  if nodeId then
    local stepId = self:GetTaskStepId(taskId, nodeId)
    local tplTaskStep = _taskStepTpl:getTplById(stepId)
    if tplTaskStep and _taskStepTpl:getIsLimitStep(tplTaskStep) then
      local infos = self:GetNodeInfoParam(taskId, nodeId)
      for i = 0, infos.Count - 1 do
        local taskInfoData = infos[i]
        if not taskInfoData.isComplate then
          return true
        end
      end
    end
  end
  return false
end

function this:getTaskNodeTagetTextById(taskId, taskNodeId, index, showProgress)
  local info = self:GetNodeInfoParamByIndex(taskId, taskNodeId, index)
  return self:getTaskNodeTagetText(info, showProgress)
end

function this:getTaskNodeTagetText(taskInfoData, showProgress)
  if not taskInfoData then
    return ""
  end
  local tplTaskTarget = _taskTargetTpl:getTplById(taskInfoData.conditionInfoId)
  if not tplTaskTarget then
    errorf(string.format("Can't get tplTaskTarget by id:%s, taskNodeId:%s", taskInfoData.conditionInfoId, taskInfoData.nodeId))
    return ""
  end
  local desc = _taskTargetTpl:getDesc(tplTaskTarget)
  if taskInfoData.sceneId == AzurWorldInstance.CurWorldId and taskInfoData.canTraceNpc == false and not math.isEmpty(taskInfoData.npcShowTime) and not math.isEmpty(taskInfoData.npcHideTime) then
    local limit = L_WordsTpl:getValue("ui_taskcondition_today", {
      [0] = math.floor(taskInfoData.npcShowTime),
      [1] = math.floor(taskInfoData.npcHideTime)
    })
    desc = string.format("%s (%s)", _taskTargetTpl:getDesc(tplTaskTarget), limit)
  end
  if showProgress and _taskTargetTpl:getParam(tplTaskTarget) == 1 then
    local maxValue = taskInfoData.maxValue
    if 0 < maxValue then
      local nowValue = taskInfoData.isComplate and maxValue or taskInfoData.nowValue
      desc = desc .. string.format("  %s/%s", nowValue, maxValue)
    end
  end
  return desc
end

function this:getPosByTaskGetNpc(taskGetNpc)
  return self:_getTaskEntityPos(taskGetNpc.taskId, taskGetNpc.npcId, taskGetNpc.sceneId, taskGetNpc.isCreateNpc)
end

function this:_getTaskEntityPos(taskId, targetId, mapId, isClientCreate, addHudHeight)
  local x, y, z = C_TaskManager.LuaGetTaskEntityPos(taskId, targetId, mapId, isClientCreate, addHudHeight)
  local res = L_Vector3.new(x, y, z)
  if res:calSqrMagnitude() < 0.001 then
    return
  end
  return res
end

function this:addTaskSubData(taskId, nodeId, subData)
  if self.taskSubData == nil then
    self.taskSubData = {}
  end
  if subData == nil then
    return
  end
  if not self.taskSubData[taskId] then
    self.taskSubData[taskId] = {}
  end
  local refId = nodeId << 32 | subData.npcId
  if not self.taskSubData[taskId][refId] then
    self.taskSubData[taskId][refId] = {}
  end
  table.insert(self.taskSubData[taskId][refId], subData)
end

function this:completeTaskSubmit(entityId, taskId, nodeId)
  L_UI:open("pageTaskSubmit", {
    entityId = entityId,
    taskId = taskId,
    nodeId = nodeId
  })
end

function this:getNeedSubItem(entityId, taskId, nodeId)
  if taskId == nil or entityId == nil then
    return nil
  end
  local needTable = {}
  local subTable = {}
  if self.taskSubData and self.taskSubData[taskId] then
    local refId = nodeId << 32 | entityId
    local subData = self.taskSubData[taskId][refId]
    if subData then
      for _, v in pairs(subData) do
        local data = v
        local conditionId = data.conditionId
        if needTable.showType == nil then
          needTable.showType = conditionId
        elseif needTable.showType ~= conditionId then
          error("\229\141\149\230\172\161\228\187\187\229\138\161\230\143\144\228\186\164\230\156\137\229\164\154\228\184\170\228\184\141\229\144\140\230\152\190\231\164\186\232\167\132\229\136\153\239\188\129")
          break
        end
        if not needTable.index then
          needTable.index = data.index
        end
        if conditionId == L_Const.taskClientEvent.submitItem then
          local itemData = {}
          itemData.showType = conditionId
          itemData.itemId = data.itemId
          itemData.needCount = data.itemCount
          itemData.index = data.index
          table.insert(subTable, itemData)
        elseif conditionId == L_Const.taskClientEvent.submitTaskItem then
          local itemData = {}
          itemData.showType = conditionId
          itemData.itemId = data.itemId
          itemData.index = data.index
          itemData.needCount = data.itemCount
          table.insert(subTable, itemData)
        elseif conditionId == L_Const.taskClientEvent.submitTypeItem then
          local itemData = {}
          itemData.showType = conditionId
          itemData.itemType = data.itemType
          itemData.needCount = data.itemCount
          itemData.index = data.index
          table.insert(subTable, itemData)
        elseif conditionId == L_Const.taskClientEvent.submitGroupItem then
          local itemData = {}
          itemData.showType = conditionId
          itemData.itemIds = L_CommonUtil.csListToTable(data.itemIds)
          itemData.itemType = data.itemType
          itemData.needCount = data.itemCount
          itemData.index = data.index
          table.insert(subTable, itemData)
        end
      end
    end
    needTable.subTable = subTable
  end
  return needTable
end

function this:gmPrintTaskExecuteNode()
  local ids = C_TaskManager.GetTaskExecuteTaskId()
  for i = 0, ids.Count - 1 do
    local str = ""
    local nodeId = C_TaskManager.GetExcuteNode(ids[i])
    local infos = self:GetNodeInfoParam(ids[i], nodeId)
    local nodeStr = string.format("[%s] nodeId : %s || inforId : ", ids[i], nodeId)
    for i = 0, infos.Count - 1 do
      nodeStr = nodeStr .. infos[i].conditionInfoId .. ", "
    end
    str = str .. nodeStr
    printf(_managerTag, str)
  end
end

function this:gmPrintTaskExecuteNodeUnderway()
  self:gmPrintTaskExecuteNode()
end

function this:getTraceTaskId2FormulaIdInfo()
end

return this
