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

INTERNAL_API.LIDCOUNCIL_CreateLootListDetailsPopupHelpers_Impl = function(deps)
  deps = type(deps) == "table" and deps or {}

  local ApplyFrameSkin = deps.ApplyFrameSkin
  local ApplyLootListToolbarButtonStyle = deps.ApplyLootListToolbarButtonStyle
  local ApplyLootListDetailActionButtonStyle = deps.ApplyLootListDetailActionButtonStyle or ApplyLootListToolbarButtonStyle
  local CreateSimpleEditBox = deps.CreateSimpleEditBox
  local GetLootListViewMode = deps.GetLootListViewMode

  local function CaptureFrameAnchorData(frame)
    local anchors = {}
    if not frame or type(frame.GetNumPoints) ~= "function" then
      return anchors
    end
    for index = 1, frame:GetNumPoints() do
      local point, relativeTo, relativePoint, xOfs, yOfs = frame:GetPoint(index)
      anchors[#anchors + 1] = {
        point = point,
        relativeTo = relativeTo,
        relativePoint = relativePoint,
        xOfs = xOfs,
        yOfs = yOfs,
      }
    end
    return anchors
  end

  local function RestoreFrameAnchorData(frame, anchors)
    if not frame then
      return
    end
    frame:ClearAllPoints()
    for _, anchor in ipairs(anchors or {}) do
      frame:SetPoint(anchor.point, anchor.relativeTo, anchor.relativePoint, anchor.xOfs, anchor.yOfs)
    end
  end

  local function RestoreLootListDetailsPane(editor)
    if not editor or not editor.lootListRightBg then
      return
    end

    local pane = editor.lootListRightBg
    if editor.__lootLedgerPopupOriginalParent then
      pane:SetParent(editor.__lootLedgerPopupOriginalParent)
      RestoreFrameAnchorData(pane, editor.__lootLedgerPopupOriginalPoints)
    end

    editor.__lootLedgerPopupOpen = nil
    if editor.RefreshLootListPage then
      editor:RefreshLootListPage()
    else
      pane:SetShown(GetLootListViewMode() == "DETAILS")
    end
  end

  local function EnsureLootListDetailsPopup(editor)
    if editor and editor.lootLedgerPopupFrame then
      return editor.lootLedgerPopupFrame
    end
    if not editor then
      return nil
    end

    local frame = CreateFrame("Frame", "LIDCOUNCIL_LootListPopup", UIParent, "BackdropTemplate")
    frame:SetSize(760, 720)
    frame:SetPoint("CENTER", 0, 0)
    frame:SetFrameStrata("FULLSCREEN_DIALOG")
    frame:SetMovable(true)
    frame:EnableMouse(true)
    frame:SetToplevel(true)
    frame:RegisterForDrag("LeftButton")
    frame:SetScript("OnDragStart", frame.StartMoving)
    frame:SetScript("OnDragStop", frame.StopMovingOrSizing)
    ApplyFrameSkin(frame)
    frame:SetScript("OnHide", function()
      RestoreLootListDetailsPane(editor)
    end)
    frame:Hide()

    local closeBtn = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate,BackdropTemplate")
    closeBtn:SetSize(78, 22)
    closeBtn:SetPoint("TOPRIGHT", -14, -14)
    closeBtn:SetText("Close")
    ApplyLootListToolbarButtonStyle(closeBtn)
    closeBtn:SetScript("OnClick", function()
      frame:Hide()
    end)
    frame.closeBtn = closeBtn

    editor.lootLedgerPopupFrame = frame
    return frame
  end

  local function OpenLootListDetailsPopup(editor, row)
    if not editor or type(row) ~= "table" then
      return
    end

    local frame = EnsureLootListDetailsPopup(editor)
    local pane = editor.lootListRightBg
    if not frame or not pane then
      return
    end
    editor.selectedLootLedgerType = row.type
    editor.selectedLootLedgerKey = row.character
    editor.selectedLootLedgerCharacter = row.character

    if not editor.__lootLedgerPopupOriginalParent or pane:GetParent() ~= frame then
      if pane:GetParent() ~= frame then
        editor.__lootLedgerPopupOriginalParent = pane:GetParent()
        editor.__lootLedgerPopupOriginalPoints = CaptureFrameAnchorData(pane)
      end
    end

    editor.__lootLedgerPopupOpen = true
    pane:SetParent(frame)
    pane:ClearAllPoints()
    pane:SetPoint("TOPLEFT", frame, "TOPLEFT", 14, -44)
    pane:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -14, 14)
    pane:Show()

    frame:Show()
    if frame.Raise then
      frame:Raise()
    end
    if editor.RefreshLootListPage then
      editor:RefreshLootListPage()
    end
  end

  local RefreshLootListLinkManager

  local function EnsureLinkManagerRows(frame, count)
    frame.__linkRows = frame.__linkRows or {}
    while #frame.__linkRows < count do
      local row = CreateFrame("Frame", nil, frame.content, "BackdropTemplate")
      row:SetSize(592, 48)
      ApplyFrameSkin(row)

      local icon = row:CreateTexture(nil, "ARTWORK")
      icon:SetSize(24, 24)
      icon:SetPoint("LEFT", 10, 0)
      icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
      row.icon = icon

      local nameText = row:CreateFontString(nil, "OVERLAY", "GameFontNormal")
      nameText:SetPoint("TOPLEFT", icon, "TOPRIGHT", 10, -7)
      nameText:SetWidth(270)
      nameText:SetJustifyH("LEFT")
      row.nameText = nameText

      local detailText = row:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
      detailText:SetPoint("TOPLEFT", nameText, "BOTTOMLEFT", 0, -2)
      detailText:SetWidth(330)
      detailText:SetJustifyH("LEFT")
      row.detailText = detailText

      local stateText = row:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
      stateText:SetPoint("TOPRIGHT", -122, -17)
      stateText:SetWidth(120)
      stateText:SetJustifyH("RIGHT")
      row.stateText = stateText

      local action = CreateFrame("Button", nil, row, "UIPanelButtonTemplate")
      action:SetSize(96, 24)
      action:SetPoint("RIGHT", -10, 0)
      ApplyLootListDetailActionButtonStyle(action, false)
      row.action = action

      frame.__linkRows[#frame.__linkRows + 1] = row
    end
    return frame.__linkRows
  end

  local function EnsureLootListLinkManager(editor)
    if editor and editor.lootLedgerLinkManager then
      return editor.lootLedgerLinkManager
    end
    if not editor then
      return nil
    end

    local frame = CreateFrame("Frame", "LIDCOUNCIL_LootListLinkManager", UIParent, "BackdropTemplate")
    frame:SetSize(660, 620)
    frame:SetPoint("CENTER", 0, 0)
    frame:SetFrameStrata("FULLSCREEN_DIALOG")
    frame:SetMovable(true)
    frame:EnableMouse(true)
    frame:SetToplevel(true)
    frame:RegisterForDrag("LeftButton")
    frame:SetScript("OnDragStart", frame.StartMoving)
    frame:SetScript("OnDragStop", frame.StopMovingOrSizing)
    ApplyFrameSkin(frame)
    frame:Hide()

    local title = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    title:SetPoint("TOPLEFT", 18, -18)
    title:SetText("Character Links")
    title:SetTextColor(1.00, 0.82, 0.24, 1)
    frame.title = title

    local subtitle = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    subtitle:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -6)
    subtitle:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -62, -42)
    subtitle:SetJustifyH("LEFT")
    subtitle:SetText("")
    frame.subtitle = subtitle

    local selectedText = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    selectedText:SetPoint("TOPLEFT", 18, -78)
    selectedText:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -18, -78)
    selectedText:SetJustifyH("LEFT")
    frame.selectedText = selectedText

    local divider = frame:CreateTexture(nil, "BORDER")
    divider:SetTexture("Interface\\Buttons\\WHITE8x8")
    divider:SetPoint("TOPLEFT", 18, -104)
    divider:SetPoint("TOPRIGHT", -18, -104)
    divider:SetHeight(1)
    divider:SetVertexColor(0.86, 0.68, 0.20, 0.36)

    local scroll = CreateFrame("ScrollFrame", nil, frame, "UIPanelScrollFrameTemplate")
    scroll:SetPoint("TOPLEFT", 18, -118)
    scroll:SetPoint("BOTTOMRIGHT", -32, 52)
    frame.scroll = scroll

    local content = CreateFrame("Frame", nil, scroll)
    content:SetSize(592, 1)
    scroll:SetScrollChild(content)
    frame.content = content

    local emptyText = content:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    emptyText:SetPoint("TOPLEFT", 10, -10)
    emptyText:SetPoint("TOPRIGHT", content, "TOPRIGHT", -10, -10)
    emptyText:SetJustifyH("LEFT")
    emptyText:SetText("")
    frame.emptyText = emptyText

    local feedback = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    feedback:SetPoint("BOTTOMLEFT", 18, 18)
    feedback:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -102, 18)
    feedback:SetJustifyH("LEFT")
    feedback:SetText("")
    frame.feedback = feedback

    local closeBtn = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
    closeBtn:SetSize(78, 26)
    closeBtn:SetPoint("BOTTOMRIGHT", -18, 14)
    closeBtn:SetText("Close")
    ApplyLootListDetailActionButtonStyle(closeBtn, false)
    closeBtn:SetScript("OnClick", function()
      frame:Hide()
    end)

    local topCloseBtn = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
    topCloseBtn:SetSize(28, 24)
    topCloseBtn:SetPoint("TOPRIGHT", -14, -14)
    topCloseBtn:SetText("X")
    ApplyLootListDetailActionButtonStyle(topCloseBtn, false)
    topCloseBtn:SetScript("OnClick", function()
      frame:Hide()
    end)

    editor.lootLedgerLinkManager = frame
    return frame
  end

  RefreshLootListLinkManager = function(frame, config)
    if not frame or type(config) ~= "table" or type(config.GetState) ~= "function" then
      return
    end
    local state = config.GetState()
    if type(state) ~= "table" then
      frame:Hide()
      return
    end

    local selectedRole = tostring(state.selectedRole or "MAIN") == "ALT" and "ALT" or "MAIN"
    local selectedCharacter = tostring(state.selectedCharacter or "?")
    frame.__linkManagerConfig = config
    frame.selectedText:SetText(string.format(
      "%s  |  %s",
      selectedCharacter,
      selectedRole == "ALT" and "ALT CHARACTER" or "MAIN CHARACTER"
    ))
    if selectedRole == "ALT" then
      frame.subtitle:SetText("Choose the Main this character belongs to. Each change is applied and synchronized as one safe update.")
    else
      frame.subtitle:SetText("Attach, move, or detach existing characters. Linked characters share the group point total.")
    end
    local visibleCandidates = {}
    for _, candidate in ipairs(state.candidates or {}) do
      if selectedRole == "MAIN" or tostring(candidate.role or "MAIN") == "MAIN" then
        visibleCandidates[#visibleCandidates + 1] = candidate
      end
    end
    table.sort(visibleCandidates, function(a, b)
      return string.lower(tostring(a and a.character or "")) < string.lower(tostring(b and b.character or ""))
    end)

    local rows = EnsureLinkManagerRows(frame, math.max(1, #visibleCandidates))
    frame.emptyText:SetShown(#visibleCandidates == 0)
    if #visibleCandidates == 0 then
      frame.emptyText:SetText(selectedRole == "ALT" and "No eligible Main characters are available." or "No other characters are available to link.")
    else
      frame.emptyText:SetText("")
    end

    for index, row in ipairs(rows) do
      local candidate = visibleCandidates[index]
      if not candidate then
        row:Hide()
      else
        row:Show()
        row:ClearAllPoints()
        row:SetPoint("TOPLEFT", 0, -((index - 1) * 54))
        if row.icon then
          row.icon:SetTexture(candidate.icon or "Interface\\Icons\\INV_Misc_QuestionMark")
          row.icon:SetTexCoord(0, 1, 0, 1)
        end
        row.nameText:SetText(tostring(candidate.character or "?"))
        row.detailText:SetText(tostring(candidate.specText or "Unknown specialization"))

        local actionLabel = nil
        local actionRole = nil
        local actionMain = nil
        local stateText = ""
        if selectedRole == "ALT" then
          if candidate.character == state.selectedMain then
            stateText = "Current Main"
          else
            stateText = "Main"
            actionLabel = "Set Main"
            actionRole = "ALT"
            actionMain = candidate.character
          end
        elseif candidate.role == "ALT" and candidate.mainCharacter == selectedCharacter then
          stateText = "Attached"
          actionLabel = "Detach"
          actionRole = "MAIN"
          actionMain = ""
        elseif candidate.role == "MAIN" and tonumber(candidate.attachedAltCount) and tonumber(candidate.attachedAltCount) > 0 then
          stateText = "Has attached alts"
        else
          stateText = candidate.mainCharacter ~= "" and "Linked elsewhere" or "Available"
          actionLabel = candidate.mainCharacter ~= "" and "Move Here" or "Attach"
          actionRole = "ALT"
          actionMain = selectedCharacter
        end
        row.stateText:SetText(stateText)
        row.stateText:SetTextColor(0.82, 0.82, 0.88, 1)
        if actionLabel and state.canEdit then
          row.action:SetShown(true)
          row.action:SetText(actionLabel)
          row.action:Enable()
          row.action:SetScript("OnClick", function()
            if type(config.ApplyChange) ~= "function" then
              return
            end
            local ok, message, mode = config.ApplyChange(candidate.character, actionRole, actionMain)
            if not ok then
              frame.feedback:SetText(tostring(message or "Could not update the character link."))
              frame.feedback:SetTextColor(1.00, 0.40, 0.30, 1)
              return
            end
            frame.feedback:SetText(tostring(message or "Character link updated."))
            frame.feedback:SetTextColor(0.42, 1.00, 0.60, 1)
            if type(config.Refresh) == "function" then
              config.Refresh()
            end
            if mode == "REQUEST_SENT" then
              frame:Hide()
            else
              RefreshLootListLinkManager(frame, config)
            end
          end)
        else
          row.action:SetShown(false)
          row.action:SetScript("OnClick", nil)
        end
      end
    end
    frame.content:SetHeight(math.max(1, #visibleCandidates * 54))
    frame.scroll:SetVerticalScroll(0)
  end

  local function OpenLootListLinkManager(editor, config)
    local frame = EnsureLootListLinkManager(editor)
    if not frame then
      return
    end
    frame:Show()
    if frame.Raise then
      frame:Raise()
    end
    RefreshLootListLinkManager(frame, config)
  end

  return {
    OpenLootListDetailsPopup = OpenLootListDetailsPopup,
    OpenLootListLinkManager = OpenLootListLinkManager,
  }
end
