local API = rawget(_G, "LIDCOUNCIL_API")
local INTERNAL_API = type(API) == "table" and type(API.__internal) == "table" and API.__internal or nil
if type(INTERNAL_API) ~= "table" then
  error("LidCouncil missing internal API registry.")
end

local shared = INTERNAL_API.LIDCOUNCIL_LootEditorShared_Impl
if type(shared) ~= "table" then
  error("LidCouncil missing loot editor shared helpers.")
end

local ApplyFrameSkin = shared.ApplyFrameSkin
local CreateCustomDropdownControl = shared.CreateCustomDropdownControl

local SCOPE_ORDER = {
  "full_profile",
  "profile_setup",
  "current_session",
  "roles_rights",
  "loot_list",
  "item_history",
  "session_history",
  "fun_awards",
}

local function Trim(value)
  local text = tostring(value or "")
  text = text:gsub("^%s+", "")
  text = text:gsub("%s+$", "")
  return text
end

local function ResolveApi(name)
  local registry = rawget(_G, "LIDCOUNCIL_API")
  return type(registry) == "table" and type(registry[name]) == "function" and registry[name] or nil
end

local function SetButtonEnabled(button, enabled)
  if not button then
    return
  end
  if enabled then
    button:Enable()
  else
    button:Disable()
  end
end

local function SetStatus(editor, text, color)
  editor.__lootSessionHostOverrideActionStatus = {
    text = tostring(text or ""),
    color = type(color) == "table" and color or { 0.82, 0.84, 0.92, 1.00 },
  }
end

local function NormalizeSelectionMap(selection)
  selection = type(selection) == "table" and selection or {}
  if selection.full_profile == true then
    return { "full_profile" }
  end
  local scopes = {}
  for _, key in ipairs(SCOPE_ORDER) do
    if key ~= "full_profile" and selection[key] == true then
      scopes[#scopes + 1] = key
    end
  end
  return scopes
end

local function CollectQueuedScopes(report)
  local queuedScopes = {}
  for _, result in ipairs(type(report) == "table" and type(report.results) == "table" and report.results or {}) do
    if type(result) == "table" and result.accepted == true
      and math.max(0, tonumber(result.transfers) or 0) > 0
      and Trim(result.scope) ~= ""
    then
      queuedScopes[#queuedScopes + 1] = Trim(result.scope)
    end
  end
  return queuedScopes
end

local function BuildScopeLookup()
  local registryProvider = ResolveApi("LIDCOUNCIL_GetProfileHostOverrideScopeRegistry")
  local registry = type(registryProvider) == "function" and registryProvider() or {}
  local lookup = {}
  for _, definition in ipairs(type(registry) == "table" and registry or {}) do
    if type(definition) == "table" and Trim(definition.key) ~= "" then
      lookup[definition.key] = definition
    end
  end
  return lookup
end

local function BuildPlanWarnings(scopes)
  local buildPlan = ResolveApi("LIDCOUNCIL_BuildProfileHostOverridePlan")
  local plan = type(buildPlan) == "function" and buildPlan(scopes) or nil
  return type(plan) == "table" and type(plan.warnings) == "table" and plan.warnings or {}
end

local function SameMember(left, right)
  return string.lower(Trim(left)) == string.lower(Trim(right))
end

local function GetOperationTime()
  if type(GetServerTime) == "function" then
    return math.max(0, tonumber(GetServerTime()) or 0)
  end
  return math.max(0, tonumber(type(time) == "function" and time() or 0) or 0)
end

local function ListContains(values, wanted)
  wanted = string.lower(Trim(wanted))
  for _, value in ipairs(type(values) == "table" and values or {}) do
    if string.lower(Trim(value)) == wanted then
      return true
    end
  end
  return false
end

local function ResolveTransferScope(transfer, scopeLookup)
  transfer = type(transfer) == "table" and transfer or {}
  local reason = string.lower(Trim(transfer.reason))
  for _, key in ipairs(SCOPE_ORDER) do
    local definition = type(scopeLookup) == "table" and scopeLookup[key] or nil
    local transport = type(definition) == "table" and definition.transport or nil
    if reason ~= "" and reason == string.lower(Trim(type(transport) == "table" and transport.reason or "")) then
      return key
    end
  end
  if transfer.hostAuthoritativeOverride ~= true then
    return nil
  end
  local archiveScope = string.upper(Trim(transfer.authoritativeArchiveScope))
  if archiveScope == "LOOT_LIST" then
    return "loot_list"
  elseif archiveScope == "SESSION_HISTORY" then
    return "session_history"
  elseif archiveScope == "FUN_AWARDS" then
    return "fun_awards"
  elseif string.upper(Trim(transfer.transferKind)) == "FULL" then
    return "full_profile"
  elseif ListContains(transfer.scopeSubdomains, "session_live_board") then
    return "item_history"
  elseif ListContains(transfer.scopeDomains, "settings") then
    return "profile_setup"
  elseif ListContains(transfer.scopeDomains, "permissions") then
    return "roles_rights"
  end
  return nil
end

local function ResolveDeliveryPhase(transfer)
  transfer = type(transfer) == "table" and transfer or {}
  local state = string.lower(Trim(transfer.state))
  if state == "acked" or state == "superseded_acked" or state == "completed_preview" then
    return "complete", "Receipt confirmed"
  elseif state == "waiting_apply" or state == "superseded_waiting_apply" then
    return "waiting_apply", "Awaiting automatic apply"
  elseif state == "waiting_ack" then
    return "waiting_ack", "Awaiting receipt"
  elseif state == "sending" then
    local sent = math.max(0, tonumber(transfer.sentChunks) or 0)
    local total = math.max(0, tonumber(transfer.totalChunks) or 0)
    local percent = total > 0 and math.min(100, math.floor(((sent / total) * 100) + 0.5)) or 0
    return "sending", string.format("Sending %d%% (%d/%d chunks)", percent, sent, total)
  elseif state == "queued" then
    return "queued", "Queued"
  elseif state == "ack_timeout" then
    local outcome = string.lower(Trim(transfer.ackTimeoutRecoveryOutcome))
    local recoveryError = Trim(transfer.ackTimeoutRecoveryError)
    if outcome == "already_aligned" or outcome == "no_transfer_needed" then
      return "complete", "Receipt revalidated"
    elseif outcome == "not_host" or outcome == "session_changed" or outcome == "member_not_joined"
      or outcome == "invalid_transfer" or outcome == "failed" or outcome == "retry_exhausted"
      or outcome == "archive_retry_exhausted" or outcome == "recovery_error"
      or (recoveryError ~= "" and transfer.ackTimeoutRecoverySucceeded ~= true)
    then
      return "failed", recoveryError ~= "" and ("Recovery failed: " .. recoveryError) or "Recovery failed"
    end
    return "recovering", "Receipt timed out; recovery active"
  elseif state == "failed" then
    local reason = Trim(transfer.terminalReason)
    if reason == "" then
      reason = Trim(transfer.failureReason)
    end
    return "failed", reason ~= "" and ("Failed: " .. reason) or "Failed"
  elseif state == "superseded" then
    return "recovering", "Replaced by a newer transfer"
  end
  return "queued", "Waiting for transport status"
end

local DELIVERY_PHASE_PRIORITY = {
  failed = 7,
  recovering = 6,
  waiting_apply = 5,
  waiting_ack = 4,
  sending = 3,
  queued = 2,
  complete = 1,
}

local function BuildDeliveryStatus(queueStatus, operation, scopeLookup)
  operation = type(operation) == "table" and operation or {}
  local target = Trim(operation.target)
  local scopes = type(operation.scopes) == "table" and operation.scopes or {}
  local sessionId = Trim(operation.sessionId)
  local startedAt = math.max(0, tonumber(operation.startedAt) or 0)
  local latestByScope = {}
  for _, transfer in ipairs(type(queueStatus) == "table" and type(queueStatus.profileTransfers) == "table"
    and queueStatus.profileTransfers or {})
  do
    local transferSessionId = Trim(type(transfer) == "table" and transfer.sessionId or "")
    local queuedAt = math.max(0, tonumber(type(transfer) == "table" and transfer.queuedAt or 0) or 0)
    if type(transfer) == "table" and SameMember(transfer.target, target)
      and (sessionId == "" or transferSessionId == "" or transferSessionId == sessionId)
      and (startedAt <= 0 or queuedAt >= startedAt)
    then
      local scope = ResolveTransferScope(transfer, scopeLookup)
      if scope then
        local current = latestByScope[scope]
        local generation = math.max(0, tonumber(transfer.generation) or 0)
        local currentGeneration = math.max(0, tonumber(type(current) == "table" and current.generation or 0) or 0)
        local currentQueuedAt = math.max(0, tonumber(type(current) == "table" and current.queuedAt or 0) or 0)
        if not current or generation > currentGeneration
          or (generation == currentGeneration and queuedAt >= currentQueuedAt)
        then
          latestByScope[scope] = transfer
        end
      end
    end
  end

  local result = {
    target = target,
    rows = {},
    overallPhase = "complete",
    matchedTransfers = 0,
  }
  local highestPriority = 0
  for _, scope in ipairs(scopes) do
    local transfer = latestByScope[scope]
    local phase, detail
    if transfer then
      result.matchedTransfers = result.matchedTransfers + 1
      phase, detail = ResolveDeliveryPhase(transfer)
    else
      phase, detail = "queued", "Waiting for transport status"
    end
    local priority = DELIVERY_PHASE_PRIORITY[phase] or 0
    if priority > highestPriority then
      highestPriority = priority
      result.overallPhase = phase
    end
    result.rows[#result.rows + 1] = {
      scope = scope,
      label = tostring(type(scopeLookup) == "table" and type(scopeLookup[scope]) == "table"
        and scopeLookup[scope].label or scope),
      phase = phase,
      detail = detail,
      transferId = Trim(type(transfer) == "table" and transfer.transferId or ""),
    }
  end
  result.complete = #result.rows > 0 and result.overallPhase == "complete"
  return result
end

local DELIVERY_PHASE_COLORS = {
  complete = "|cff55ee77",
  sending = "|cff55bbee",
  queued = "|cffb8c0d0",
  waiting_ack = "|cffffcc55",
  waiting_apply = "|cffffcc55",
  recovering = "|cffffa64d",
  failed = "|cffff6655",
}

local function FormatDeliveryStatus(delivery)
  if type(delivery) ~= "table" or #delivery.rows == 0 then
    return ""
  end
  local lines = { "Delivery to " .. Trim(delivery.target) .. ":" }
  for _, row in ipairs(delivery.rows) do
    local color = DELIVERY_PHASE_COLORS[row.phase] or "|cffd0d4df"
    lines[#lines + 1] = string.format("%s%s: %s|r", color, tostring(row.label or row.scope), tostring(row.detail or ""))
  end
  return table.concat(lines, "\n")
end

local function IsDeliveryActive(delivery)
  if type(delivery) ~= "table" then
    return false
  end
  for _, row in ipairs(type(delivery.rows) == "table" and delivery.rows or {}) do
    local phase = Trim(type(row) == "table" and row.phase or "")
    if phase ~= "" and phase ~= "complete" and phase ~= "failed" then
      return true
    end
  end
  return false
end

local function IsOperationActive(operation, delivery)
  if type(operation) ~= "table" then
    return false
  end
  if type(delivery) ~= "table" then
    -- Queue telemetry can lag behind an accepted dispatch. Keep the operation
    -- locked until a delivery row appears or the bounded observer expires it.
    return true
  end
  return IsDeliveryActive(delivery)
end

local function BuildExpiredDelivery(lastDelivery)
  local expired = {
    target = Trim(type(lastDelivery) == "table" and lastDelivery.target or ""),
    rows = {},
    overallPhase = "failed",
    matchedTransfers = 0,
    complete = false,
  }
  for _, row in ipairs(type(lastDelivery) == "table" and type(lastDelivery.rows) == "table"
    and lastDelivery.rows or {})
  do
    expired.rows[#expired.rows + 1] = {
      scope = type(row) == "table" and row.scope or "",
      label = type(row) == "table" and row.label or "Data section",
      phase = "failed",
      detail = "Transport record ended without a retained receipt; verify before retrying",
    }
  end
  return expired
end

local function BuildMissingDelivery(operation, scopeLookup)
  local missing = {
    target = Trim(type(operation) == "table" and operation.target or ""),
    rows = {},
    overallPhase = "failed",
    matchedTransfers = 0,
    complete = false,
  }
  for _, scope in ipairs(type(operation) == "table" and type(operation.scopes) == "table"
    and operation.scopes or {})
  do
    missing.rows[#missing.rows + 1] = {
      scope = scope,
      label = tostring(type(scopeLookup) == "table" and type(scopeLookup[scope]) == "table"
        and scopeLookup[scope].label or scope),
      phase = "failed",
      detail = "No transport record appeared; refresh member state before retrying",
    }
  end
  return missing
end

local function GetTrackedDelivery(editor, target, context, scopeLookup)
  local operationKey = string.lower(Trim(target))
  local operations = editor and editor.__lootSessionHostOverrideOperations or nil
  local operation = type(operations) == "table" and operations[operationKey] or nil
  local activeSessionId = Trim(type(context) == "table" and type(context.activeSession) == "table"
    and context.activeSession.id or "")
  if type(operation) == "table" and Trim(operation.sessionId) ~= activeSessionId then
    operations[operationKey] = nil
    operation = nil
  end
  if type(operation) ~= "table" then
    return nil, nil
  end
  local delivery = BuildDeliveryStatus(editor.lootSessionCommQueueStatusData, operation, scopeLookup)
  if delivery.matchedTransfers > 0 then
    operation.lastDelivery = delivery
  elseif type(operation.lastDelivery) == "table" then
    delivery = IsDeliveryActive(operation.lastDelivery)
      and BuildExpiredDelivery(operation.lastDelivery)
      or operation.lastDelivery
    operation.lastDelivery = delivery
  elseif GetOperationTime() - math.max(0, tonumber(operation.startedAt) or 0) >= 8 then
    delivery = BuildMissingDelivery(operation, scopeLookup)
    operation.lastDelivery = delivery
  end
  return operation, delivery
end

local function BuildMemberEntries(context, candidates)
  local activeSession = type(context) == "table" and context.activeSession or nil
  local hostKey = string.lower(Trim(type(activeSession) == "table" and activeSession.host or ""))
  local candidateLookup = {}
  for _, candidate in ipairs(type(candidates) == "table" and candidates or {}) do
    if type(candidate) == "table" and Trim(candidate.memberKey) ~= "" then
      candidateLookup[string.lower(Trim(candidate.memberKey))] = candidate
    end
  end
  local entries = {}
  for memberKey, member in pairs(type(activeSession) == "table" and type(activeSession.members) == "table" and activeSession.members or {}) do
    local key = Trim(memberKey)
    local normalized = string.lower(key)
    local status = string.upper(Trim(type(member) == "table" and member.status or "JOINED"))
    if key ~= "" and normalized ~= hostKey and status == "JOINED" then
      local candidate = candidateLookup[normalized]
      local specName = Trim(type(candidate) == "table" and candidate.specName or (type(member) == "table" and member.specName or ""))
      local role = Trim(type(candidate) == "table" and candidate.role or (type(member) == "table" and member.role or ""))
      local detail = specName ~= "" and specName or role
      entries[#entries + 1] = {
        key = key,
        label = detail ~= "" and (key .. " | " .. detail) or key,
      }
    end
  end
  table.sort(entries, function(left, right)
    return string.lower(left.key) < string.lower(right.key)
  end)
  return entries
end

local function FindMemberEntry(entries, memberKey)
  local wanted = string.lower(Trim(memberKey))
  for _, entry in ipairs(type(entries) == "table" and entries or {}) do
    if string.lower(Trim(entry.key)) == wanted then
      return entry
    end
  end
  return nil
end

local function RefreshScopeRow(row, selected, enabled)
  if not row then
    return
  end
  row.__selected = selected == true
  row.check:SetChecked(row.__selected)
  row.label:SetTextColor(
    row.__selected and 1.00 or 0.86,
    row.__selected and 0.86 or 0.88,
    row.__selected and 0.32 or 0.94,
    enabled and 1.00 or 0.48
  )
  if row.SetBackdropColor then
    row:SetBackdropColor(row.__selected and 0.18 or 0.04, row.__selected and 0.13 or 0.05, row.__selected and 0.04 or 0.08, 0.96)
  end
  if row.SetBackdropBorderColor then
    row:SetBackdropBorderColor(
      row.__selected and 0.92 or 0.28,
      row.__selected and 0.66 or 0.40,
      row.__selected and 0.18 or 0.58,
      enabled and 0.92 or 0.42
    )
  end
  if enabled then
    row:Enable()
  else
    row:Disable()
  end
end

local function RefreshPanel(editor, context)
  local ensurePanel = INTERNAL_API.LIDCOUNCIL_EnsureLootSessionHostOverridePanel_Impl
  local frame = type(ensurePanel) == "function" and ensurePanel(editor) or nil
  if not frame then
    return
  end

  context = type(context) == "table" and context or {}
  editor.__lootSessionHostOverrideContext = context
  local access = type(context.access) == "table" and context.access or {}
  local available = type(context.activeSession) == "table" and context.activeSessionIsHost == true
    and access.canManageSession == true and context.syntheticSession ~= true
  editor.__lootSessionHostOverrideAvailable = available
  frame:SetShown(available)
  if not available then
    return
  end

  local inCombat = type(InCombatLockdown) == "function" and InCombatLockdown() and true or false
  local entries = BuildMemberEntries(context, editor.lootSessionAllSyncCandidates)
  frame.__memberEntries = entries
  local selectedEntry = FindMemberEntry(entries, editor.__lootSessionHostOverrideTarget)
  if not selectedEntry then
    selectedEntry = entries[1]
    editor.__lootSessionHostOverrideTarget = selectedEntry and selectedEntry.key or nil
  end

  frame.targetDropdown:SetMenuBuilder(function(dropdown)
    local menuEntries = {}
    for _, entry in ipairs(frame.__memberEntries or {}) do
      local memberEntry = entry
      menuEntries[#menuEntries + 1] = {
        text = memberEntry.label,
        checked = Trim(memberEntry.key) == Trim(editor.__lootSessionHostOverrideTarget),
        func = function()
          editor.__lootSessionHostOverrideTarget = memberEntry.key
          editor.__lootSessionHostOverrideActionStatus = nil
          dropdown:SetSelectedValue(memberEntry.key)
          dropdown:SetText(memberEntry.label)
          RefreshPanel(editor, editor.__lootSessionHostOverrideContext)
        end,
      }
    end
    return {
      width = math.max(260, tonumber(dropdown.dropdownWidth) or 260),
      enableSearch = #menuEntries > 8,
      searchPlaceholder = "Search joined member",
      entries = menuEntries,
    }
  end)
  frame.targetDropdown:SetSelectedValue(selectedEntry and selectedEntry.key or nil)
  frame.targetDropdown:SetText(selectedEntry and selectedEntry.label or "No joined member available")
  frame.targetDropdown:SetEnabled(#entries > 0 and not inCombat)

  editor.__lootSessionHostOverrideScopes = type(editor.__lootSessionHostOverrideScopes) == "table"
    and editor.__lootSessionHostOverrideScopes
    or {}
  for _, row in ipairs(frame.scopeRows or {}) do
    RefreshScopeRow(row, editor.__lootSessionHostOverrideScopes[row.scopeKey] == true, not inCombat)
  end

  local scopes = NormalizeSelectionMap(editor.__lootSessionHostOverrideScopes)
  local scopeLookup = BuildScopeLookup()
  local labels = {}
  for _, key in ipairs(scopes) do
    labels[#labels + 1] = tostring(scopeLookup[key] and scopeLookup[key].label or key)
  end
  if selectedEntry and #labels > 0 then
    local summary = "Ready: replace " .. table.concat(labels, ", ") .. " on " .. selectedEntry.key .. "."
    local warnings = BuildPlanWarnings(scopes)
    if #warnings > 0 then
      summary = summary .. "\nWarning: " .. table.concat(warnings, " ")
    end
    frame.summary:SetText(summary)
    frame.summary:SetTextColor(1.00, 0.80, 0.30, 1.00)
  elseif not selectedEntry then
    frame.summary:SetText("No joined member is currently available for a targeted override.")
    frame.summary:SetTextColor(0.76, 0.78, 0.84, 1.00)
  else
    frame.summary:SetText("Select one or more data sections to replace.")
    frame.summary:SetTextColor(0.76, 0.78, 0.84, 1.00)
  end

  local status = editor.__lootSessionHostOverrideActionStatus
  local operation, delivery = GetTrackedDelivery(editor, selectedEntry and selectedEntry.key or "", context, scopeLookup)
  local deliveryText = FormatDeliveryStatus(delivery)
  local deliveryActive = IsOperationActive(operation, delivery)
  if deliveryText ~= "" then
    if inCombat then
      deliveryText = deliveryText .. "\n|cffffb84dNew overrides are unavailable in combat; active delivery remains tracked.|r"
    end
    frame.status:SetText(deliveryText)
    frame.status:SetTextColor(0.86, 0.88, 0.94, 1.00)
  elseif inCombat then
    frame.status:SetText("Unavailable in combat. The selections are preserved until combat ends.")
    frame.status:SetTextColor(1.00, 0.72, 0.30, 1.00)
  elseif type(status) == "table" and Trim(status.text) ~= "" then
    local color = type(status.color) == "table" and status.color or { 0.82, 0.84, 0.92, 1.00 }
    frame.status:SetText(status.text)
    frame.status:SetTextColor(color[1] or 0.82, color[2] or 0.84, color[3] or 0.92, color[4] or 1.00)
  else
    frame.status:SetText("The receiver applies a valid active-host override automatically and returns normal transfer acknowledgements.")
    frame.status:SetTextColor(0.70, 0.76, 0.86, 1.00)
  end
  frame.executeButton:SetText(deliveryActive and "Override In Progress" or "Override Selected Data")
  SetButtonEnabled(frame.executeButton, selectedEntry ~= nil and #scopes > 0 and not inCombat and not deliveryActive)
end

local function ExecuteOverride(editor)
  local target = Trim(editor.__lootSessionHostOverrideTarget)
  local scopes = NormalizeSelectionMap(editor.__lootSessionHostOverrideScopes)
  local pushOverride = ResolveApi("LIDCOUNCIL_PushProfileHostOverrideFlow")
  if target == "" or #scopes == 0 or type(pushOverride) ~= "function" then
    SetStatus(editor, "Host override could not start because its target, scope, or transport is unavailable.", { 1.00, 0.44, 0.38, 1.00 })
    RefreshPanel(editor, editor.__lootSessionHostOverrideContext)
    return
  end
  if type(InCombatLockdown) == "function" and InCombatLockdown() then
    SetStatus(editor, "Host overrides cannot start in combat.", { 1.00, 0.72, 0.30, 1.00 })
    RefreshPanel(editor, editor.__lootSessionHostOverrideContext)
    return
  end
  local scopeLookup = BuildScopeLookup()
  local existingOperation, existingDelivery = GetTrackedDelivery(
    editor,
    target,
    editor.__lootSessionHostOverrideContext,
    scopeLookup
  )
  if IsOperationActive(existingOperation, existingDelivery) then
    SetStatus(editor, "Wait for the active override to complete or fail before sending another override to this member.", { 1.00, 0.72, 0.30, 1.00 })
    RefreshPanel(editor, editor.__lootSessionHostOverrideContext)
    return
  end

  local startedAt = GetOperationTime()
  local called, complete, report = pcall(pushOverride, target, scopes)
  if called and type(report) == "table" and math.max(0, tonumber(report.acceptedSteps) or 0) > 0 then
    local acceptedScopes = CollectQueuedScopes(report)
    if #acceptedScopes > 0 then
      editor.__lootSessionHostOverrideOperations = type(editor.__lootSessionHostOverrideOperations) == "table"
        and editor.__lootSessionHostOverrideOperations
        or {}
      local activeSession = type(editor.__lootSessionHostOverrideContext) == "table"
        and editor.__lootSessionHostOverrideContext.activeSession
        or nil
      editor.__lootSessionHostOverrideOperations[string.lower(target)] = {
        target = target,
        scopes = acceptedScopes,
        sessionId = Trim(type(activeSession) == "table" and activeSession.id or ""),
        startedAt = startedAt,
        expectedTransfers = math.max(0, tonumber(report.queuedTransfers) or 0),
      }
    end
  end
  if not called then
    SetStatus(editor, "Host override failed: " .. tostring(complete), { 1.00, 0.44, 0.38, 1.00 })
  elseif type(report) == "table" and math.max(0, tonumber(report.queuedTransfers) or 0) <= 0 then
    SetStatus(editor, string.format(
      "No transport was queued for %s. Controls were unlocked; refresh member state before retrying.",
      target
    ), { 1.00, 0.72, 0.30, 1.00 })
  elseif complete == true and type(report) == "table" then
    SetStatus(editor, string.format(
      "Queued %d acknowledged transfer(s) across %d section(s) for %s.",
      math.max(0, tonumber(report.queuedTransfers) or 0),
      math.max(0, tonumber(report.acceptedSteps) or 0),
      target
    ), { 0.38, 0.94, 0.54, 1.00 })
  elseif type(report) == "table" and math.max(0, tonumber(report.acceptedSteps) or 0) > 0 then
    SetStatus(editor, string.format(
      "Partially queued for %s: %d section(s) accepted, %d failed. Review Sync Monitor delivery details.",
      target,
      math.max(0, tonumber(report.acceptedSteps) or 0),
      #(type(report.failures) == "table" and report.failures or {})
    ), { 1.00, 0.72, 0.30, 1.00 })
  else
    local failure = type(report) == "table" and type(report.failures) == "table" and report.failures[1] or nil
    local errorText = type(report) == "table" and Trim(report.error) or ""
    if errorText == "" and type(failure) == "table" then
      errorText = Trim(failure.error)
    end
    SetStatus(editor, "Host override was not queued. " .. (errorText ~= "" and errorText or "Review Sync Monitor diagnostics."), { 1.00, 0.44, 0.38, 1.00 })
  end
  RefreshPanel(editor, editor.__lootSessionHostOverrideContext)
  if editor.LayoutLootSessionPage then
    editor:LayoutLootSessionPage()
  end
end

local function ConfirmOverride(editor)
  local target = Trim(editor.__lootSessionHostOverrideTarget)
  local scopes = NormalizeSelectionMap(editor.__lootSessionHostOverrideScopes)
  if target == "" or #scopes == 0 then
    return
  end
  local scopeLookup = BuildScopeLookup()
  local existingOperation, existingDelivery = GetTrackedDelivery(
    editor,
    target,
    editor.__lootSessionHostOverrideContext,
    scopeLookup
  )
  if IsOperationActive(existingOperation, existingDelivery) then
    SetStatus(editor, "An override is already in progress for this member.", { 1.00, 0.72, 0.30, 1.00 })
    RefreshPanel(editor, editor.__lootSessionHostOverrideContext)
    return
  end
  local labels = {}
  for _, key in ipairs(scopes) do
    labels[#labels + 1] = tostring(scopeLookup[key] and scopeLookup[key].label or key)
  end
  if type(StaticPopupDialogs) ~= "table" or type(StaticPopup_Show) ~= "function" then
    SetStatus(editor, "Confirmation dialog is unavailable; no data was sent.", { 1.00, 0.44, 0.38, 1.00 })
    RefreshPanel(editor, editor.__lootSessionHostOverrideContext)
    return
  end
  local warnings = BuildPlanWarnings(scopes)
  local warningText = #warnings > 0 and ("\n\nWarning: " .. table.concat(warnings, " ")) or ""
  if not StaticPopupDialogs.LIDCOUNCIL_PROFILE_HOST_OVERRIDE_CONFIRM then
    StaticPopupDialogs.LIDCOUNCIL_PROFILE_HOST_OVERRIDE_CONFIRM = {
      text = "",
      button1 = "Override Data",
      button2 = CANCEL or "Cancel",
      timeout = 0,
      whileDead = 1,
      hideOnEscape = 1,
      preferredIndex = 3,
      OnAccept = function(dialog)
        local data = dialog and dialog.data
        if type(data) == "table" and data.editor then
          ExecuteOverride(data.editor)
        end
      end,
    }
  end
  StaticPopupDialogs.LIDCOUNCIL_PROFILE_HOST_OVERRIDE_CONFIRM.text =
    "Replace %s on %s with the host copy?\n\nThis bypasses comparison safeguards. The member applies the data automatically after combat."
      .. warningText
  StaticPopup_Show(
    "LIDCOUNCIL_PROFILE_HOST_OVERRIDE_CONFIRM",
    table.concat(labels, ", "),
    target,
    { editor = editor }
  )
end

local function EnsurePanel(editor)
  if not editor then
    return nil
  end
  if editor.lootSessionHostOverrideFrame then
    return editor.lootSessionHostOverrideFrame
  end
  local parent = editor.lootSessionRightContent or editor.lootSessionRightBg or UIParent
  local frame = CreateFrame("Frame", nil, parent, "BackdropTemplate")
  ApplyFrameSkin(frame)
  if frame.SetBackdropColor then
    frame:SetBackdropColor(0.035, 0.04, 0.055, 0.98)
  end
  editor.lootSessionHostOverrideFrame = frame

  frame.title = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
  frame.title:SetText("Targeted Host Override")
  frame.description = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  frame.description:SetJustifyH("LEFT")
  frame.description:SetWordWrap(true)
  frame.description:SetText("Emergency recovery tool: choose one joined member and replace only the selected shared-profile sections with the host copy.")
  frame.warning = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  frame.warning:SetJustifyH("LEFT")
  frame.warning:SetWordWrap(true)
  frame.warning:SetText("This bypasses difference recommendations. It does not alter the existing precise repair workflow and always requires confirmation.")
  frame.warning:SetTextColor(1.00, 0.62, 0.28, 1.00)
  frame.targetLabel = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  frame.targetLabel:SetText("Joined member")
  frame.targetDropdown = CreateCustomDropdownControl(editor, frame, {
    width = 340,
    buttonHeight = 22,
    text = "No joined member available",
    maxVisibleEntries = 12,
  })
  frame.scopeLabel = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  frame.scopeLabel:SetText("Data to replace")
  frame.scopeRows = {}

  local scopeLookup = BuildScopeLookup()
  for _, key in ipairs(SCOPE_ORDER) do
    local definition = scopeLookup[key] or { key = key, label = key, description = "" }
    local row = CreateFrame("Button", nil, frame, "BackdropTemplate")
    row:SetBackdrop({
      bgFile = "Interface\\Buttons\\WHITE8x8",
      edgeFile = "Interface\\Buttons\\WHITE8x8",
      edgeSize = 1,
    })
    row:RegisterForClicks("LeftButtonUp")
    row.scopeKey = key
    row.scopeDescription = tostring(definition.description or "")
    row.check = CreateFrame("CheckButton", nil, row, "UICheckButtonTemplate")
    row.check:SetSize(22, 22)
    row.check:EnableMouse(false)
    row.label = row:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    row.label:SetJustifyH("LEFT")
    row.label:SetText(tostring(definition.label or key))
    row:SetScript("OnClick", function(self)
      editor.__lootSessionHostOverrideScopes = type(editor.__lootSessionHostOverrideScopes) == "table"
        and editor.__lootSessionHostOverrideScopes
        or {}
      if self.scopeKey == "full_profile" then
        local selectFull = editor.__lootSessionHostOverrideScopes.full_profile ~= true
        editor.__lootSessionHostOverrideScopes = selectFull and { full_profile = true } or {}
      else
        editor.__lootSessionHostOverrideScopes.full_profile = nil
        editor.__lootSessionHostOverrideScopes[self.scopeKey] = editor.__lootSessionHostOverrideScopes[self.scopeKey] ~= true
      end
      editor.__lootSessionHostOverrideActionStatus = nil
      RefreshPanel(editor, editor.__lootSessionHostOverrideContext)
      if editor.LayoutLootSessionPage then
        editor:LayoutLootSessionPage()
      end
    end)
    row:SetScript("OnEnter", function(self)
      if type(GameTooltip) ~= "table" then
        return
      end
      GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
      GameTooltip:AddLine(self.label:GetText() or "Host Override", 1.00, 0.82, 0.28, true)
      GameTooltip:AddLine(self.scopeDescription, 0.92, 0.92, 0.96, true)
      GameTooltip:Show()
    end)
    row:SetScript("OnLeave", function()
      if type(GameTooltip) == "table" then
        GameTooltip:Hide()
      end
    end)
    frame.scopeRows[#frame.scopeRows + 1] = row
  end

  frame.summary = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  frame.summary:SetJustifyH("LEFT")
  frame.summary:SetWordWrap(true)
  frame.executeButton = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
  frame.executeButton:SetSize(230, 24)
  frame.executeButton:SetText("Override Selected Data")
  frame.executeButton.__lid_customBg = { 0.18, 0.08, 0.04, 0.96 }
  frame.executeButton.__lid_customHover = { 0.98, 0.46, 0.20, 0.24 }
  frame.executeButton.__lid_customPushed = { 0.34, 0.10, 0.05, 0.98 }
  frame.executeButton.__lid_customBorder = { 0.86, 0.34, 0.18, 0.92 }
  frame.executeButton.__lid_customText = { 1.00, 0.90, 0.82, 1.00 }
  frame.executeButton:SetScript("OnClick", function()
    ConfirmOverride(editor)
  end)
  frame.status = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  frame.status:SetJustifyH("LEFT")
  frame.status:SetWordWrap(true)
  frame:Hide()
  return frame
end

local function LayoutPanel(editor, top, width)
  local frame = EnsurePanel(editor)
  if not frame or editor.__lootSessionHostOverrideAvailable ~= true then
    if frame then
      frame:Hide()
    end
    return top
  end
  frame:Show()
  width = math.max(300, tonumber(width) or 300)
  frame:ClearAllPoints()
  frame:SetPoint("TOPLEFT", 18, top)
  frame:SetWidth(width)

  local y = -12
  frame.title:ClearAllPoints()
  frame.title:SetPoint("TOPLEFT", 14, y)
  frame.title:SetWidth(width - 28)
  y = y - 24
  frame.description:ClearAllPoints()
  frame.description:SetPoint("TOPLEFT", 14, y)
  frame.description:SetWidth(width - 28)
  y = y - math.max(18, math.ceil(frame.description:GetStringHeight() or 0)) - 6
  frame.warning:ClearAllPoints()
  frame.warning:SetPoint("TOPLEFT", 14, y)
  frame.warning:SetWidth(width - 28)
  y = y - math.max(18, math.ceil(frame.warning:GetStringHeight() or 0)) - 12

  frame.targetLabel:ClearAllPoints()
  frame.targetLabel:SetPoint("TOPLEFT", 14, y - 3)
  frame.targetDropdown:ClearAllPoints()
  frame.targetDropdown:SetPoint("TOPLEFT", 132, y)
  local dropdownWidth = math.max(150, width - 146)
  frame.targetDropdown.dropdownWidth = dropdownWidth
  if frame.targetDropdown.SetDropdownWidth then
    frame.targetDropdown:SetDropdownWidth(dropdownWidth)
  else
    frame.targetDropdown:SetWidth(dropdownWidth)
  end
  y = y - 34

  frame.scopeLabel:ClearAllPoints()
  frame.scopeLabel:SetPoint("TOPLEFT", 14, y)
  y = y - 24
  local columns = width >= 840 and 3 or (width >= 540 and 2 or 1)
  local gap = 8
  local rowWidth = math.floor((width - 28 - ((columns - 1) * gap)) / columns)
  local rowHeight = 26
  for index, row in ipairs(frame.scopeRows or {}) do
    local column = (index - 1) % columns
    local rowIndex = math.floor((index - 1) / columns)
    row:ClearAllPoints()
    row:SetPoint("TOPLEFT", 14 + (column * (rowWidth + gap)), y - (rowIndex * (rowHeight + 6)))
    row:SetSize(rowWidth, rowHeight)
    row.check:ClearAllPoints()
    row.check:SetPoint("LEFT", 2, 0)
    row.label:ClearAllPoints()
    row.label:SetPoint("LEFT", row.check, "RIGHT", 2, 0)
    row.label:SetPoint("RIGHT", -6, 0)
  end
  y = y - (math.ceil(#(frame.scopeRows or {}) / columns) * (rowHeight + 6)) - 6

  frame.summary:ClearAllPoints()
  frame.summary:SetPoint("TOPLEFT", 14, y)
  frame.summary:SetWidth(width - 28)
  y = y - math.max(18, math.ceil(frame.summary:GetStringHeight() or 0)) - 10
  frame.executeButton:ClearAllPoints()
  frame.executeButton:SetPoint("TOPLEFT", 14, y)
  y = y - 34
  frame.status:ClearAllPoints()
  frame.status:SetPoint("TOPLEFT", 14, y)
  frame.status:SetWidth(width - 28)
  y = y - math.max(18, math.ceil(frame.status:GetStringHeight() or 0)) - 14
  frame:SetHeight(math.abs(y))
  return top - frame:GetHeight() - 18
end

INTERNAL_API.LIDCOUNCIL_NormalizeProfileHostOverrideViewSelection_Impl = NormalizeSelectionMap
INTERNAL_API.LIDCOUNCIL_CollectQueuedProfileHostOverrideScopes_Impl = CollectQueuedScopes
INTERNAL_API.LIDCOUNCIL_BuildProfileHostOverrideDeliveryStatus_Impl = BuildDeliveryStatus
INTERNAL_API.LIDCOUNCIL_IsProfileHostOverrideDeliveryActive_Impl = IsDeliveryActive
INTERNAL_API.LIDCOUNCIL_IsProfileHostOverrideOperationActive_Impl = IsOperationActive
INTERNAL_API.LIDCOUNCIL_EnsureLootSessionHostOverridePanel_Impl = EnsurePanel
INTERNAL_API.LIDCOUNCIL_RefreshLootSessionHostOverridePanel_Impl = RefreshPanel
INTERNAL_API.LIDCOUNCIL_LayoutLootSessionHostOverridePanel_Impl = LayoutPanel
