local EnsureApiRegistry = rawget(_G, "LIDCOUNCIL_EnsureApiRegistry")
local API, INTERNAL_API
if type(EnsureApiRegistry) == "function" then
  API, INTERNAL_API = EnsureApiRegistry()
else
  API = rawget(_G, "LIDCOUNCIL_API")
  if type(API) ~= "table" then
    API = {}
    _G.LIDCOUNCIL_API = API
  end
  if type(API.__internal) ~= "table" then
    API.__internal = {}
  end
  INTERNAL_API = API.__internal
end

INTERNAL_API.LIDCOUNCIL_CreateOutboundFlushPolicyHelpers_Impl = function(deps)
  deps = type(deps) == "table" and deps or {}
  local GetQueue = type(deps.GetQueue) == "function" and deps.GetQueue or function()
    return {}
  end
  local GetIntervalSeconds = type(deps.GetIntervalSeconds) == "function" and deps.GetIntervalSeconds or function()
    return 0
  end
  local GetQueueItemPriority = type(deps.GetQueueItemPriority) == "function" and deps.GetQueueItemPriority or function()
    return 10
  end
  local ResolveProfileSyncTransferLane = type(deps.ResolveProfileSyncTransferLane) == "function"
    and deps.ResolveProfileSyncTransferLane
    or function()
      return "live"
    end
  local IsChunkedProfileSyncKind = type(deps.IsChunkedProfileSyncKind) == "function" and deps.IsChunkedProfileSyncKind
    or function()
      return false
    end
  local ProfileSyncIdleIntervalSeconds = math.max(0, tonumber(deps.ProfileSyncIdleIntervalSeconds) or 0)

  local function QueueHasOnlyChunkedProfileSyncTraffic()
    local queue = GetQueue()
    if type(queue) ~= "table" or #queue == 0 then
      return false
    end
    for _, queued in ipairs(queue) do
      if not IsChunkedProfileSyncKind(type(queued) == "table" and queued.kind or "") then
        return false
      end
    end
    return true
  end

  local function GetQueuedOutboundCommDelay(lastAttemptedItem, wasThrottled, wasFailureRetry)
    local queue = GetQueue()
    local nextItem = type(queue) == "table" and queue[1] or nil
    local delay = GetIntervalSeconds()
    if type(nextItem) == "table" then
      local nextPriority = GetQueueItemPriority(nextItem)
      if nextPriority <= 5 then
        delay = math.min(delay, 0.05)
      elseif nextPriority <= 10 then
        delay = math.min(delay, 0.08)
      end
    end

    if wasThrottled then
      delay = math.max(1.0, GetIntervalSeconds())
      local resolvedLane = ResolveProfileSyncTransferLane(type(lastAttemptedItem) == "table" and lastAttemptedItem.metadata or nil)
      if type(lastAttemptedItem) == "table" and IsChunkedProfileSyncKind(lastAttemptedItem.kind) then
        local retryCount = math.max(
          1,
          tonumber(lastAttemptedItem.throttleCount) or 0,
          tonumber(lastAttemptedItem.failureRetryCount) or 0
        )
        if resolvedLane == "archive" then
          delay = math.max(delay, math.min(6.0, 1.5 + retryCount))
        elseif resolvedLane == "stats" then
          delay = math.max(delay, math.min(4.5, 0.85 + (retryCount * 0.65)))
        else
          delay = math.max(delay, math.min(2.2, 0.35 + (retryCount * 0.25)))
        end
      end
      return delay
    end

    if wasFailureRetry then
      -- A failed packet carries its own not-before timestamp. Keep the normal
      -- cadence for unrelated ready work instead of spinning across the queue.
      return math.max(delay, GetIntervalSeconds())
    end

    if type(nextItem) == "table"
      and IsChunkedProfileSyncKind(nextItem.kind)
      and QueueHasOnlyChunkedProfileSyncTraffic()
    then
      local resolvedLane = ResolveProfileSyncTransferLane(type(nextItem) == "table" and nextItem.metadata or nil)
      if resolvedLane == "archive" then
        delay = math.max(delay, ProfileSyncIdleIntervalSeconds * 1.8)
      elseif resolvedLane == "stats" then
        delay = math.min(delay, ProfileSyncIdleIntervalSeconds * 1.15)
      else
        delay = math.min(delay, ProfileSyncIdleIntervalSeconds * 0.75)
      end
    end
    return delay
  end

  local function ResolveOutboundCommFlushSchedule(queueLength, now, delaySeconds, currentDueAt)
    if math.max(0, tonumber(queueLength) or 0) == 0 then
      return false, true, 0
    end
    local resolvedDelay = math.max(0, tonumber(delaySeconds) or 0)
    local dueAt = (tonumber(now) or 0) + resolvedDelay
    if math.max(0, tonumber(currentDueAt) or 0) > 0
      and dueAt >= ((tonumber(currentDueAt) or 0) - 0.001)
    then
      return false, false, dueAt
    end
    return true, false, dueAt
  end

  return {
    GetQueuedOutboundCommDelay = GetQueuedOutboundCommDelay,
    ResolveOutboundCommFlushSchedule = ResolveOutboundCommFlushSchedule,
  }
end
