local Localization = CS.GameEntry.Localization
local PushData = require("DataCenter.PushNoticeManager.PushData")
local PushNoticeManager = BaseClass("PushNoticeManager")
local __MIN_ALARM_TIME = 600
local _PERSON_AMY_DELAYTIME = 14400
local __resBuildingSet = {
  BuildingTypes.LW_BUILD_FARMLAND,
  BuildingTypes.LW_BUILD_QUARRY,
  BuildingTypes.LW_BUILD_GOLD_MILL,
  BuildingTypes.LW_BUILD_SMELTERY,
  BuildingTypes.LW_BUILD_TRAINING_CENTER,
  BuildingTypes.LW_BUILD_MATERIALS_WORKERSHOP,
  BuildingTypes.LW_BUILD_PETROLEUM,
  BuildingTypes.LW_BUILD_DOMINATOR_TRAIN
}
local ShieldPushConfig = {
  ItemIdMap = {
    200410,
    200406,
    200411,
    200412
  },
  StatusIdMap = {
    500000,
    600080,
    500001,
    500002
  }
}

function PushNoticeManager:__init()
  self.pushDefines = {
    [4100001] = {
      pushId = 4100001,
      calcTimeFunc = self.CalcResBuildingFullTimeSec
    },
    [4100002] = {
      pushId = 4100002,
      calcTimeFunc = self.CalcTruckFullTimeSec
    },
    [4100029] = {
      pushId = 4100029,
      calcTimeFunc = self.CalcStaminaFullTimeSec
    },
    [4100033] = {
      pushId = 4100033,
      calcTimeFunc = self.CalcBuildingUpgradeTimeSec
    },
    [4100034] = {
      pushId = 4100034,
      calcTimeFunc = self.CalcResearchDoneTimeSec
    },
    [4100040] = {
      pushId = 4100040,
      calcTimeFunc = self.CalcMilitaryCampFullTimeSec
    },
    [4101100] = {
      pushId = 4101100,
      calcTimeFunc = self.CalcPersonalArmyTimeSec
    },
    [4100041] = {
      pushId = 4100041,
      calcTimeFunc = self.CalcCollectTimeSec
    },
    [4100042] = {
      pushId = 4100042,
      calcTimeFunc = self.CalcShieldTimeSec
    },
    [4100043] = {
      pushId = 4100043,
      calcTimeFunc = self.CalcActLotteryOpenBigRewardTimeSec
    }
  }
  
  function self.__onPlayerStaminaUpdate()
    self:TryPushNotice(4100029)
  end
  
  function self.__onProductLineCollect(buildingUuid)
    local buildingData = DataCenter.BuildManager:GetBuildingDataByUuid(buildingUuid)
    if buildingData and table.indexof(__resBuildingSet, buildingData.itemId) then
      self:TryPushNotice(4100001)
    end
  end
  
  function self.__onHangRewardRefreshed()
    self:TryPushNotice(4100002)
  end
  
  function self.__onUpdateBuildingData(buildingUuid)
    local buildingData = DataCenter.BuildManager:GetBuildingDataByUuid(buildingUuid)
    if buildingData and buildingData.itemId == BuildingTypes.LW_BUILD_MILITARY_CAMP then
      self:TryPushNotice(4100040)
    end
    self:TryPushNotice(4100033)
  end
  
  function self.__onUpdateQueueData(queueData)
    if queueData.type == NewQueueType.Science then
      self:TryPushNotice(4100034)
    end
  end
  
  function self.__onSingleMarchStateUpdate(marchUuid)
    self:TryPushNotice(4100041)
  end
  
  function self.__onItemUseSuccess(itemId)
  end
  
  function self.__onActLotteryOpenTipGet(actLotteryId)
    self:TryPushNotice(4100043)
  end
  
  self.CheckNoticeTimers = {}
  EventManager:GetInstance():AddListener(EventId.APP_APPLICATION_PAUSE, self.OnApplicationPause, self)
  EventManager:GetInstance():AddListener(EventId.PlayerStaminaUpdate, self.__onPlayerStaminaUpdate, self)
  EventManager:GetInstance():AddListener(EventId.ProductLineCollect, self.__onProductLineCollect, self)
  EventManager:GetInstance():AddListener(EventId.HangRewardRefreshed, self.__onHangRewardRefreshed, self)
  EventManager:GetInstance():AddListener(EventId.UPDATE_BUILD_DATA, self.__onUpdateBuildingData, self)
  EventManager:GetInstance():AddListener(EventId.UPDATE_QUEUE_DATA, self.__onUpdateQueueData, self)
  EventManager:GetInstance():AddListener(EventId.SingleMarchStateUpdate, self.__onSingleMarchStateUpdate, self)
  EventManager:GetInstance():AddListener(EventId.UseItemSuccess, self.__onItemUseSuccess, self)
  EventManager:GetInstance():AddListener(EventId.ActLotteryTryOpenTip, self.__onActLotteryOpenTipGet, self)
end

function PushNoticeManager:__delete()
  EventManager:GetInstance():RemoveListener(EventId.APP_APPLICATION_PAUSE, self.OnApplicationPause, self)
  EventManager:GetInstance():RemoveListener(EventId.PlayerStaminaUpdate, self.__onPlayerStaminaUpdate, self)
  EventManager:GetInstance():RemoveListener(EventId.ProductLineCollect, self.__onProductLineCollect, self)
  EventManager:GetInstance():RemoveListener(EventId.HangRewardRefreshed, self.__onHangRewardRefreshed, self)
  EventManager:GetInstance():RemoveListener(EventId.UPDATE_BUILD_DATA, self.__onUpdateBuildingData, self)
  EventManager:GetInstance():RemoveListener(EventId.UPDATE_QUEUE_DATA, self.__onUpdateQueueData, self)
  EventManager:GetInstance():RemoveListener(EventId.SingleMarchStateUpdate, self.__onSingleMarchStateUpdate, self)
  EventManager:GetInstance():RemoveListener(EventId.UseItemSuccess, self.__onItemUseSuccess, self)
  EventManager:GetInstance():RemoveListener(EventId.ActLotteryTryOpenTip, self.__onActLotteryOpenTipGet, self)
  self.__onPlayerStaminaUpdate = nil
  self.__onProductLineCollect = nil
  self.__onHangRewardRefreshed = nil
  self.__onUpdateBuildingData = nil
  self.__onUpdateQueueData = nil
  self.pushDefines = nil
  for k, timer in pairs(self.CheckNoticeTimers) do
    timer:Stop()
  end
  self.CheckNoticeTimers = nil
end

function PushNoticeManager:OnEnterGame()
  self:CancelAllNotice()
  for pushId, _ in pairs(self.pushDefines) do
    self:TryPushNotice(pushId)
  end
end

function PushNoticeManager.OnApplicationPause(isPaused)
  if not isPaused then
    DataCenter.PushNoticeManager:OnEnterGame()
  end
end

function PushNoticeManager:TryPushNotice(pushId)
  local isSettingsOn = DataCenter.PushSettingsManager:IsPushOn(pushId)
  if not isSettingsOn then
    return
  end
  local define = self.pushDefines[pushId]
  if not define then
    return
  end
  local timeSec = define.calcTimeFunc()
  if timeSec then
    self:PushNotice(pushId, timeSec)
    self:CheckSetNoticeTimer(pushId, timeSec)
  else
    self:CancelNotice(pushId)
    self:CheckStopNoticeTimer(pushId)
  end
end

function PushNoticeManager:PushNotice(pushId, timeSec)
  local pushType = LocalController:instance():getValue(TableName.APS_PUSH, pushId, "push_type")
  local pushBody = Localization:GetString(LocalController:instance():getValue(TableName.APS_PUSH, pushId, "dialogId"))
  local param = {}
  param.type = tostring(pushType)
  param.time = math.ceil(timeSec)
  param.body = pushBody
  param.soundKey = ""
  param.pushType = tostring(pushType)
  param.playerMark = LuaEntry.Player.pushMark
  param.gameUid = LuaEntry.Player.uid
  param.pushId = tostring(pushId)
  local strJson = require("rapidjson").encode(param)
  CS.PushNoticeManager.PushNotice(strJson)
end

function PushNoticeManager:CancelNotice(pushId)
  local pushType = LocalController:instance():getValue(TableName.APS_PUSH, pushId, "push_type")
  local param = {}
  param.type = tostring(pushType)
  param.pushType = tostring(pushType)
  param.pushId = tostring(pushId)
  local strJson = require("rapidjson").encode(param)
  CS.PushNoticeManager.CancelNotice(strJson)
end

function PushNoticeManager:CancelAllNotice()
  CS.PushNoticeManager.ClearAllNotice()
end

function PushNoticeManager:CheckNoticeBySettings(pushSettingsId)
  local pushIds = LocalController:instance():getValue(TableName.APS_PUSH_SETTINGS, pushSettingsId, "push_ids")
  for _, pushId in ipairs(pushIds) do
    self:TryPushNotice(pushId)
  end
end

function PushNoticeManager:CancelNoticeBySettings(pushSettingsId)
  local pushIds = LocalController:instance():getValue(TableName.APS_PUSH_SETTINGS, pushSettingsId, "push_ids")
  for _, pushId in ipairs(pushIds) do
    self:CancelNotice(pushId)
  end
end

function PushNoticeManager.CalcStaminaFullTimeSec()
  local config = DataCenter.ArmyFormationDataManager:GetConfigData()
  local stamina = LuaEntry.Player:GetCurStamina()
  if config and stamina < config.FormationStaminaMax then
    local deltaNum = config.FormationStaminaMax - stamina
    local endTime = deltaNum * config.FormationStaminaUpdateTime
    if 0 < endTime then
      return endTime
    end
  end
  return nil
end

function PushNoticeManager.CalcResBuildingFullTimeSec()
  local minSec
  local serverTime = UITimeManager:GetInstance():GetServerTime()
  for _, buildingId in ipairs(__resBuildingSet) do
    local buildingDatas = DataCenter.BuildManager:GetBuildingDatasByBuildingId(buildingId)
    for _, buildingData in ipairs(buildingDatas) do
      local prodState = DataCenter.ProductLineManager:GetState(buildingData.uuid)
      if prodState == ProductLineState.Normal and buildingData.productEndTime then
        local restSec = (buildingData.productEndTime - serverTime) / 1000
        if restSec >= __MIN_ALARM_TIME and (not minSec or minSec > restSec) then
          minSec = restSec
        end
      end
    end
  end
  return minSec
end

function PushNoticeManager.CalcTruckFullTimeSec()
  if DataCenter.StageManager.lastIdleRewardTimeStamp then
    local serverTime = UITimeManager:GetInstance():GetServerTime()
    local restTime = serverTime - DataCenter.StageManager.lastIdleRewardTimeStamp
    if restTime < DataCenter.StageManager.hangUpMaxTime then
      local restSec = (DataCenter.StageManager.hangUpMaxTime - restTime) / 1000
      if restSec >= __MIN_ALARM_TIME then
        return restSec
      end
    end
  end
  return nil
end

function PushNoticeManager.CalcBuildingUpgradeTimeSec()
  local minSec
  local serverTime = UITimeManager:GetInstance():GetServerTime()
  local buildingDatas = DataCenter.BuildManager:GetAllBuildData()
  for _, buildingData in pairs(buildingDatas) do
    if buildingData:IsUpgrading() then
      local restSec = (buildingData.updateTime - serverTime) / 1000
      if restSec >= __MIN_ALARM_TIME and (not minSec or minSec > restSec) then
        minSec = restSec
      end
    end
  end
  return minSec
end

function PushNoticeManager.CalcResearchDoneTimeSec()
  local minSec
  local serverTime = UITimeManager:GetInstance():GetServerTime()
  local queueDatas = DataCenter.QueueDataManager:GetQueueDatasByType(NewQueueType.Science)
  for _, queueData in ipairs(queueDatas) do
    if queueData:GetQueueState() == NewQueueState.Work then
      local restSec = (queueData.endTime - serverTime) / 1000
      if restSec >= __MIN_ALARM_TIME and (not minSec or minSec > restSec) then
        minSec = restSec
      end
    end
  end
  return minSec
end

function PushNoticeManager.CalcMilitaryCampFullTimeSec()
  local minSec
  local serverTime = UITimeManager:GetInstance():GetServerTime()
  local buildingDatas = DataCenter.BuildManager:GetBuildingDatasByBuildingId(BuildingTypes.LW_BUILD_MILITARY_CAMP)
  for _, buildingData in ipairs(buildingDatas) do
    local prodState = DataCenter.ProductLineManager:GetState(buildingData.uuid)
    if prodState == ProductLineState.Normal and buildingData.productEndTime then
      local restSec = (buildingData.productEndTime - serverTime) / 1000
      if restSec >= __MIN_ALARM_TIME and (not minSec or minSec > restSec) then
        minSec = restSec
      end
    end
  end
  return minSec
end

function PushNoticeManager.CalcPersonalArmyTimeSec()
  local minSeconds = LuaEntry.DataConfig:TryGetNum("person_arms_race", "k4", 1)
  local data = DataCenter.ActivityPersonalArmsDataManager:GetCurData(24)
  if not data then
    return nil
  end
  local curTime = UITimeManager:GetInstance():GetServerSeconds()
  local leftTime = data.stage_end_time - curTime
  if leftTime < 0 then
    return nil
  end
  local delayTime = leftTime
  if minSeconds >= leftTime then
    delayTime = leftTime + _PERSON_AMY_DELAYTIME
  end
  return delayTime
end

function PushNoticeManager.CalcCollectTimeSec()
  local marchList = CS.SceneManager.MarchDataMgr:GetOwnerMarches()
  if marchList ~= nil then
    local min
    for _, march in pairs(marchList) do
      if march:GetMarchTargetType() == MarchTargetType.COLLECT and march:GetMarchStatus() == MarchStatus.COLLECTING then
        if min then
          min = math.min(min, march.endTime)
        else
          min = march.endTime
        end
      end
    end
    if min then
      local serverTime = UITimeManager:GetInstance():GetServerTime()
      return (min - serverTime) / 1000
    end
  end
end

function PushNoticeManager.CalcShieldTimeSec()
  return false
end

function PushNoticeManager.CalcActLotteryOpenBigRewardTimeSec()
  local curTime = UITimeManager:GetInstance():GetServerTime()
  local triggerTime
  local nextTipTime = DataCenter.ActLotteryDataManager.pushNoticActIdTime
  if nextTipTime and curTime < nextTipTime then
    triggerTime = math.floor((nextTipTime - curTime) / 1000)
    triggerTime = toInt(triggerTime)
  end
  return triggerTime
end

function PushNoticeManager:CheckSetNoticeTimer(pushId, delayTime)
  self:CheckStopNoticeTimer(pushId)
  if pushId == 4101100 then
    local minSeconds = LuaEntry.DataConfig:TryGetNum("person_arms_race", "k4", 1)
    local noticeTime = UITimeManager:GetInstance():GetServerTime() + delayTime - minSeconds
    
    function self.armyNoticeDelayTimeFunc()
      local serverTime = UITimeManager:GetInstance():GetServerTime()
      if serverTime > noticeTime then
        self:CancelNotice(pushId)
        self:CheckStopNoticeTimer()
        self:TryPushNotice(pushId)
      end
    end
    
    local timer = TimerManager:GetInstance():GetTimer(1, self.armyNoticeDelayTimeFunc, self, false, false, false)
    timer:Start()
    self.CheckNoticeTimers[pushId] = timer
  end
end

function PushNoticeManager:CheckStopNoticeTimer(pushId)
  if self.CheckNoticeTimers[pushId] then
    self.CheckNoticeTimers[pushId]:Stop()
    self.CheckNoticeTimers[pushId] = nil
  end
end

return PushNoticeManager
