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

local coordinatorState = {
  registrations = {},
  pending = {},
  nextRegistrationOrder = 0,
  flushRunning = false,
  queuedTotal = 0,
  coalescedTotal = 0,
  cancelledTotal = 0,
  flushedTotal = 0,
  failedTotal = 0,
  lastFlushAt = 0,
  lastFailureAt = 0,
  lastFailureChannel = "",
  lastFailureReason = "",
}

local function TrimText(value)
  return tostring(value or ""):match("^%s*(.-)%s*$")
end

local function NormalizeChannel(value)
  return string.upper(TrimText(value))
end

local function GetNow()
  if type(GetTime) == "function" then
    return tonumber(GetTime()) or 0
  end
  return 0
end

local function IsCombatLocked()
  return type(InCombatLockdown) == "function" and InCombatLockdown() and true or false
end

local function RegisterChannel(channel, owner, handler)
  local normalizedChannel = NormalizeChannel(channel)
  local normalizedOwner = TrimText(owner)
  if normalizedChannel == "" or normalizedOwner == "" or type(handler) ~= "function" then
    return false, "invalid_registration"
  end

  local current = coordinatorState.registrations[normalizedChannel]
  if type(current) == "table" and current.owner ~= normalizedOwner then
    return false, "owner_mismatch"
  end
  if type(current) ~= "table" then
    coordinatorState.nextRegistrationOrder = coordinatorState.nextRegistrationOrder + 1
    current = {
      channel = normalizedChannel,
      owner = normalizedOwner,
      order = coordinatorState.nextRegistrationOrder,
    }
    coordinatorState.registrations[normalizedChannel] = current
  end
  current.handler = handler
  return true
end

local function QueueChannel(channel, reason)
  local normalizedChannel = NormalizeChannel(channel)
  if type(coordinatorState.registrations[normalizedChannel]) ~= "table" then
    return false, "unregistered_channel"
  end

  local pending = coordinatorState.pending[normalizedChannel]
  if type(pending) == "table" then
    pending.count = math.max(1, tonumber(pending.count) or 1) + 1
    local resolvedReason = TrimText(reason)
    if resolvedReason ~= "" then
      pending.reason = resolvedReason
    end
    coordinatorState.coalescedTotal = coordinatorState.coalescedTotal + 1
    return true, "coalesced"
  end

  coordinatorState.pending[normalizedChannel] = {
    channel = normalizedChannel,
    reason = TrimText(reason),
    queuedAt = GetNow(),
    count = 1,
  }
  coordinatorState.queuedTotal = coordinatorState.queuedTotal + 1
  return true, "queued"
end

local function CancelChannel(channel)
  local normalizedChannel = NormalizeChannel(channel)
  if type(coordinatorState.pending[normalizedChannel]) ~= "table" then
    return false
  end
  coordinatorState.pending[normalizedChannel] = nil
  coordinatorState.cancelledTotal = coordinatorState.cancelledTotal + 1
  return true
end

local function ReportHandlerFailure(channel, failureReason)
  coordinatorState.failedTotal = coordinatorState.failedTotal + 1
  coordinatorState.lastFailureAt = GetNow()
  coordinatorState.lastFailureChannel = NormalizeChannel(channel)
  coordinatorState.lastFailureReason = tostring(failureReason or "handler_failed")
  if type(geterrorhandler) == "function" then
    local errorHandler = geterrorhandler()
    if type(errorHandler) == "function" then
      errorHandler(coordinatorState.lastFailureReason)
    end
  end
end

local function FlushPendingChannels(reason)
  if coordinatorState.flushRunning or IsCombatLocked() then
    return false, 0
  end
  if TrimText(reason) == "player_regen_enabled"
    and type(INTERNAL_API.LIDCOUNCIL_GetCombatSyncInboxStatus_Impl) == "function"
  then
    local inboxStatus = INTERNAL_API.LIDCOUNCIL_GetCombatSyncInboxStatus_Impl(nil, {
      pruneExpired = false,
    })
    if type(inboxStatus) == "table"
      and (inboxStatus.flushRunning == true or math.max(0, tonumber(inboxStatus.totalItems) or 0) > 0)
    then
      return false, 0
    end
  end

  local ordered = {}
  for channel, pending in pairs(coordinatorState.pending) do
    local registration = coordinatorState.registrations[channel]
    if type(registration) == "table" and type(registration.handler) == "function" then
      ordered[#ordered + 1] = {
        channel = channel,
        order = tonumber(registration.order) or 0,
        registration = registration,
        pending = pending,
      }
    end
  end
  table.sort(ordered, function(left, right)
    if left.order == right.order then
      return left.channel < right.channel
    end
    return left.order < right.order
  end)

  coordinatorState.flushRunning = true
  local flushedCount = 0
  for _, entry in ipairs(ordered) do
    coordinatorState.pending[entry.channel] = nil
    local ok, failureReason = pcall(entry.registration.handler, {
      channel = entry.channel,
      reason = TrimText(reason) ~= "" and TrimText(reason) or entry.pending.reason,
      queuedAt = tonumber(entry.pending.queuedAt) or 0,
      requestCount = math.max(1, tonumber(entry.pending.count) or 1),
    })
    if ok then
      flushedCount = flushedCount + 1
    else
      coordinatorState.pending[entry.channel] = entry.pending
      ReportHandlerFailure(entry.channel, failureReason)
    end
  end
  coordinatorState.flushRunning = false
  coordinatorState.flushedTotal = coordinatorState.flushedTotal + flushedCount
  coordinatorState.lastFlushAt = GetNow()
  return flushedCount > 0, flushedCount
end

local function GetStatus()
  local channels = {}
  local pendingCount = 0
  for channel, registration in pairs(coordinatorState.registrations) do
    local pending = coordinatorState.pending[channel]
    if type(pending) == "table" then
      pendingCount = pendingCount + 1
    end
    channels[#channels + 1] = {
      channel = channel,
      owner = registration.owner,
      order = tonumber(registration.order) or 0,
      pending = type(pending) == "table",
      requestCount = type(pending) == "table" and math.max(1, tonumber(pending.count) or 1) or 0,
    }
  end
  table.sort(channels, function(left, right)
    return left.order < right.order
  end)
  return {
    combatLocked = IsCombatLocked(),
    flushRunning = coordinatorState.flushRunning == true,
    channelCount = #channels,
    pendingCount = pendingCount,
    channels = channels,
    queuedTotal = coordinatorState.queuedTotal,
    coalescedTotal = coordinatorState.coalescedTotal,
    cancelledTotal = coordinatorState.cancelledTotal,
    flushedTotal = coordinatorState.flushedTotal,
    failedTotal = coordinatorState.failedTotal,
    lastFlushAt = coordinatorState.lastFlushAt,
    lastFailureAt = coordinatorState.lastFailureAt,
    lastFailureChannel = coordinatorState.lastFailureChannel,
    lastFailureReason = coordinatorState.lastFailureReason,
  }
end

local eventFrame = CreateFrame("Frame")
eventFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
eventFrame:SetScript("OnEvent", function()
  FlushPendingChannels("player_regen_enabled")
end)

INTERNAL_API.LIDCOUNCIL_RegisterCombatUiRefreshChannel_Impl = RegisterChannel
INTERNAL_API.LIDCOUNCIL_QueueCombatUiRefreshChannel_Impl = QueueChannel
INTERNAL_API.LIDCOUNCIL_CancelCombatUiRefreshChannel_Impl = CancelChannel
INTERNAL_API.LIDCOUNCIL_FlushCombatUiRefreshChannels_Impl = FlushPendingChannels
INTERNAL_API.LIDCOUNCIL_GetCombatUiRefreshStatus_Impl = GetStatus
