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_CreateOutboundSessionTelemetryHelpers_Impl = function(deps)
  deps = type(deps) == "table" and deps or {}
  local stats = type(deps.Stats) == "table" and deps.Stats or {}
  local TrimText = type(deps.TrimText) == "function" and deps.TrimText or function(value)
    return tostring(value or "")
  end
  local NormalizeCharacterKey = type(deps.NormalizeCharacterKey) == "function" and deps.NormalizeCharacterKey or TrimText
  local GetNow = type(deps.GetNow) == "function" and deps.GetNow or function()
    return 0
  end
  local GetActiveSessionId = type(deps.GetActiveSessionId) == "function" and deps.GetActiveSessionId or function()
    return ""
  end
  local GetLaneTelemetry = type(deps.GetLaneTelemetry) == "function" and deps.GetLaneTelemetry or function()
    return {}
  end
  local GetOpcodeTelemetry = type(deps.GetOpcodeTelemetry) == "function" and deps.GetOpcodeTelemetry or function()
    return {}
  end
  local GetMemberTelemetry = type(deps.GetMemberTelemetry) == "function" and deps.GetMemberTelemetry or function()
    return {}
  end
  local GetDeferredEditorRefreshTimerFallbackTotal = type(deps.GetDeferredEditorRefreshTimerFallbackTotal) == "function"
    and deps.GetDeferredEditorRefreshTimerFallbackTotal
    or function()
      return 0
    end

  local function EnsureOutboundSessionTelemetryBaseline(sessionIdOverride)
    local sessionId = TrimText(sessionIdOverride)
    if sessionId == "" then
      sessionId = TrimText(GetActiveSessionId())
    end
    local baseline = type(stats.sessionTelemetryBaseline) == "table" and stats.sessionTelemetryBaseline or nil
    if type(baseline) == "table" and TrimText(baseline.sessionId) == sessionId then
      return baseline
    end
    baseline = {
      sessionId = sessionId,
      startedAt = GetNow(),
      totals = {
        attempted = math.max(0, tonumber(stats.attemptedTotal) or 0),
        sent = math.max(0, tonumber(stats.sentTotal) or 0),
        throttled = math.max(0, tonumber(stats.throttledTotal) or 0),
        failed = math.max(0, tonumber(stats.failedTotal) or 0),
        bytesAttempted = math.max(0, tonumber(stats.bytesAttempted) or 0),
        bytesSent = math.max(0, tonumber(stats.bytesSent) or 0),
        staleSessionBoundPrunedTotal = math.max(0, tonumber(stats.staleSessionBoundPrunedTotal) or 0),
        archivePressureDeferredTotal = math.max(0, tonumber(stats.archivePressureDeferredTotal) or 0),
        archiveTargetPacingPreemptionsTotal = math.max(0,
          tonumber(type(stats.archiveTargetPacing) == "table" and stats.archiveTargetPacing.preemptionsTotal or 0) or 0
        ),
        obsoleteProfileQueuePrunedTotal = math.max(0, tonumber(stats.obsoleteProfileQueuePrunedTotal) or 0),
        timerFallbackTotal = math.max(0, tonumber(stats.timerFallbackTotal) or 0),
        profileAckTimeoutTimerFallbackTotal = math.max(0, tonumber(stats.profileAckTimeoutTimerFallbackTotal) or 0),
        deferredEditorRefreshTimerFallbackTotal = math.max(0,
          tonumber(GetDeferredEditorRefreshTimerFallbackTotal()) or 0),
      },
      lanes = GetLaneTelemetry(),
      opcodes = GetOpcodeTelemetry(),
      members = GetMemberTelemetry(),
    }
    stats.sessionTelemetryBaseline = baseline
    return baseline
  end

  local function GetOutboundSessionTelemetry(sessionIdOverride)
    local baseline = EnsureOutboundSessionTelemetryBaseline(sessionIdOverride)
    local function subtractCounters(current, previous)
      current = type(current) == "table" and current or {}
      previous = type(previous) == "table" and previous or {}
      return {
        queuedTotal = math.max(0, (tonumber(current.queuedTotal) or 0) - (tonumber(previous.queuedTotal) or 0)),
        attempted = math.max(0, (tonumber(current.attempted) or 0) - (tonumber(previous.attempted) or 0)),
        sent = math.max(0, (tonumber(current.sent) or 0) - (tonumber(previous.sent) or 0)),
        throttled = math.max(0, (tonumber(current.throttled) or 0) - (tonumber(previous.throttled) or 0)),
        failed = math.max(0, (tonumber(current.failed) or 0) - (tonumber(previous.failed) or 0)),
        payloadRejected = math.max(0, (tonumber(current.payloadRejected) or 0) - (tonumber(previous.payloadRejected) or 0)),
        bytesQueued = math.max(0, (tonumber(current.bytesQueued) or 0) - (tonumber(previous.bytesQueued) or 0)),
        bytesAttempted = math.max(0, (tonumber(current.bytesAttempted) or 0) - (tonumber(previous.bytesAttempted) or 0)),
        bytesSent = math.max(0, (tonumber(current.bytesSent) or 0) - (tonumber(previous.bytesSent) or 0)),
        bytesRejected = math.max(0, (tonumber(current.bytesRejected) or 0) - (tonumber(previous.bytesRejected) or 0)),
      }
    end
    local currentTotals = {
      attempted = math.max(0, tonumber(stats.attemptedTotal) or 0),
      sent = math.max(0, tonumber(stats.sentTotal) or 0),
      throttled = math.max(0, tonumber(stats.throttledTotal) or 0),
      failed = math.max(0, tonumber(stats.failedTotal) or 0),
      bytesAttempted = math.max(0, tonumber(stats.bytesAttempted) or 0),
      bytesSent = math.max(0, tonumber(stats.bytesSent) or 0),
    }
    local totals = subtractCounters(currentTotals, baseline.totals)
    local currentLanes = GetLaneTelemetry()
    local laneTelemetry = {}
    for _, lane in ipairs({ "live", "bootstrap", "archive", "stats", "control" }) do
      laneTelemetry[lane] = subtractCounters(currentLanes[lane], type(baseline.lanes) == "table" and baseline.lanes[lane] or nil)
    end
    local currentOpcodes = GetOpcodeTelemetry()
    local baselineOpcodesByKind = {}
    for _, opcode in ipairs(type(baseline.opcodes) == "table" and baseline.opcodes.opcodes or {}) do
      local kind = string.lower(TrimText(type(opcode) == "table" and opcode.kind or ""))
      if kind ~= "" then
        baselineOpcodesByKind[kind] = opcode
      end
    end
    local opcodeTelemetry = {}
    for _, opcode in ipairs(type(currentOpcodes.opcodes) == "table" and currentOpcodes.opcodes or {}) do
      local kind = TrimText(type(opcode) == "table" and opcode.kind or "")
      local diff = subtractCounters(opcode, baselineOpcodesByKind[string.lower(kind)])
      diff.kind = kind
      if kind ~= "" and (diff.queuedTotal > 0 or diff.attempted > 0 or diff.sent > 0 or diff.payloadRejected > 0) then
        opcodeTelemetry[#opcodeTelemetry + 1] = diff
      end
    end
    table.sort(opcodeTelemetry, function(left, right)
      if left.bytesSent ~= right.bytesSent then
        return left.bytesSent > right.bytesSent
      end
      if left.bytesAttempted ~= right.bytesAttempted then
        return left.bytesAttempted > right.bytesAttempted
      end
      if left.queuedTotal ~= right.queuedTotal then
        return left.queuedTotal > right.queuedTotal
      end
      return string.lower(left.kind) < string.lower(right.kind)
    end)
    local currentMembers = GetMemberTelemetry()
    local baselineMembersByKey = {}
    for _, member in ipairs(type(baseline.members) == "table" and baseline.members.members or {}) do
      local memberKey = string.lower(NormalizeCharacterKey(type(member) == "table" and member.member or ""))
      if memberKey ~= "" then
        baselineMembersByKey[memberKey] = member
      end
    end
    local members = {}
    for _, member in ipairs(type(currentMembers.members) == "table" and currentMembers.members or {}) do
      local memberName = NormalizeCharacterKey(type(member) == "table" and member.member or "")
      local diff = subtractCounters(member, baselineMembersByKey[string.lower(memberName)])
      diff.member = memberName
      if memberName ~= "" and (diff.attempted > 0 or diff.sent > 0) then
        members[#members + 1] = diff
      end
    end
    table.sort(members, function(left, right)
      if left.bytesSent ~= right.bytesSent then
        return left.bytesSent > right.bytesSent
      end
      if left.attempted ~= right.attempted then
        return left.attempted > right.attempted
      end
      return string.lower(left.member) < string.lower(right.member)
    end)
    return {
      active = TrimText(baseline.sessionId) ~= "",
      sessionId = TrimText(baseline.sessionId),
      startedAt = math.max(0, tonumber(baseline.startedAt) or 0),
      attemptedTotal = totals.attempted,
      sentTotal = totals.sent,
      throttledTotal = totals.throttled,
      failedTotal = totals.failed,
      bytesAttempted = totals.bytesAttempted,
      bytesSent = totals.bytesSent,
      staleSessionBoundPrunedTotal = math.max(0,
        (tonumber(stats.staleSessionBoundPrunedTotal) or 0)
          - (tonumber(baseline.totals.staleSessionBoundPrunedTotal) or 0)
      ),
      archivePressureDeferredTotal = math.max(0,
        (tonumber(stats.archivePressureDeferredTotal) or 0)
          - (tonumber(baseline.totals.archivePressureDeferredTotal) or 0)
      ),
      archiveTargetPacingPreemptionsTotal = math.max(0,
        (tonumber(type(stats.archiveTargetPacing) == "table" and stats.archiveTargetPacing.preemptionsTotal or 0) or 0)
          - (tonumber(baseline.totals.archiveTargetPacingPreemptionsTotal) or 0)
      ),
      obsoleteProfileQueuePrunedTotal = math.max(0,
        (tonumber(stats.obsoleteProfileQueuePrunedTotal) or 0)
          - (tonumber(baseline.totals.obsoleteProfileQueuePrunedTotal) or 0)
      ),
      timerFallbackTotal = math.max(0,
        (tonumber(stats.timerFallbackTotal) or 0)
          - (tonumber(baseline.totals.timerFallbackTotal) or 0)
      ),
      profileAckTimeoutTimerFallbackTotal = math.max(0,
        (tonumber(stats.profileAckTimeoutTimerFallbackTotal) or 0)
          - (tonumber(baseline.totals.profileAckTimeoutTimerFallbackTotal) or 0)
      ),
      deferredEditorRefreshTimerFallbackTotal = math.max(0,
        (tonumber(GetDeferredEditorRefreshTimerFallbackTotal()) or 0)
          - (tonumber(baseline.totals.deferredEditorRefreshTimerFallbackTotal) or 0)
      ),
      outboundLaneTelemetry = laneTelemetry,
      outboundOpcodeTelemetry = {
        maxTrackedOpcodes = math.max(1, tonumber(currentOpcodes.maxTrackedOpcodes) or 48),
        opcodes = opcodeTelemetry,
      },
      outboundMemberTelemetry = {
        maxTrackedMembers = math.max(1, tonumber(currentMembers.maxTrackedMembers) or 24),
        members = members,
        group = subtractCounters(currentMembers.group, type(baseline.members) == "table" and baseline.members.group or nil),
        other = subtractCounters(currentMembers.other, type(baseline.members) == "table" and baseline.members.other or nil),
      },
    }
  end

  return {
    EnsureOutboundSessionTelemetryBaseline = EnsureOutboundSessionTelemetryBaseline,
    GetOutboundSessionTelemetry = GetOutboundSessionTelemetry,
  }
end
