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 RequireApi = shared.RequireApi
local BindMouseWheelScroll = shared.BindMouseWheelScroll
local RootDB = shared.RootDB
local ApplyFrameSkin = shared.ApplyFrameSkin
local MakeYellowSubHeader = shared.MakeYellowSubHeader
local GetCharacterKey = shared.GetCharacterKey
local GetEnabledLootProfileName = shared.GetEnabledLootProfileName or RequireApi("LIDCOUNCIL_GetEnabledLootProfileName", _G.LIDCOUNCIL_GetEnabledLootProfileName)
local GetLootProfile = shared.GetLootProfile
local GetPrimaryLootProfileName = shared.GetPrimaryLootProfileName
local GetLootProfileNames = shared.GetLootProfileNames
local IsLootProfileVisibleInEditor = shared.IsLootProfileVisibleInEditor or function(_, profileName)
  return profileName ~= nil and profileName ~= ""
end
local GetLootProfileAccessInfo = shared.GetLootProfileAccessInfo
local SetCurrentLootProfile = shared.SetCurrentLootProfile
local CreateLootProfile = shared.CreateLootProfile
local DeleteLootProfile = shared.DeleteLootProfile
local CopyLootProfile = shared.CopyLootProfile
local SetLootProfileEnabled = shared.SetLootProfileEnabled
local SetLootProfileRaid = shared.SetLootProfileRaid
local AddLootRollOption = shared.AddLootRollOption
local UpdateLootRollOption = shared.UpdateLootRollOption
local RemoveLootRollOption = shared.RemoveLootRollOption
local UpdateLootPointMode = shared.UpdateLootPointMode
local UpdateLootLidTableRow = shared.UpdateLootLidTableRow
local AddLootPointRule = shared.AddLootPointRule
local RemoveLootPointRule = shared.RemoveLootPointRule
local StartLootSession = shared.StartLootSession
local StopLootSession = shared.StopLootSession
local GetActiveLootSession = shared.GetActiveLootSession
local AddLootLedgerEntry = shared.AddLootLedgerEntry
local RemoveLootLedgerEntry = shared.RemoveLootLedgerEntry
local GetLootLedgerCharacters = shared.GetLootLedgerCharacters
local ResolveOptionalApiFunction = shared.ResolveOptionalApiFunction
local CreateCustomDropdownControl = shared.CreateCustomDropdownControl
local TrimText = shared.TrimText
local FormatDateTime = shared.FormatDateTime
local FormatDuration = shared.FormatDuration
local CreateSimpleEditBox = shared.CreateSimpleEditBox
local SetListButtonSelected = shared.SetListButtonSelected
local SetTextListButtonTextColor = shared.SetTextListButtonTextColor
local EnsureTextListButtons = shared.EnsureTextListButtons
local CreateSectionShell = shared.CreateSectionShell
local ClampLayoutValue = shared.ClampLayoutValue
local GetResponsiveSectionLayout = shared.GetResponsiveSectionLayout
local SetControlWidth = shared.SetControlWidth
local GetFontStringWidth = shared.GetFontStringWidth
local CreateSectionDivider = shared.CreateSectionDivider
local FlowLayoutControls = shared.FlowLayoutControls
local LayoutRollOptionRow = shared.LayoutRollOptionRow
local LayoutLidTableEditorRow = shared.LayoutLidTableEditorRow
local BuildRollOptionsText = shared.BuildRollOptionsText
local DEFAULT_ROLL_OPTION_ICON_CHOICES = shared.DEFAULT_ROLL_OPTION_ICON_CHOICES
local ResolveTextureAsset = shared.ResolveTextureAsset
local ResolveDefaultRollOptionIcon = shared.ResolveDefaultRollOptionIcon
local ResolveRollOptionIcon = shared.ResolveRollOptionIcon
local GetRollOptionIconLabel = shared.GetRollOptionIconLabel
local EnsureRollOptionRows = shared.EnsureRollOptionRows
local EnsureLidTableEditorRows = shared.EnsureLidTableEditorRows
local ExtractItemID = shared.ExtractItemID
local ExtractItemLinkName = shared.ExtractItemLinkName
local FormatPointRuleItemLabel = shared.FormatPointRuleItemLabel
local FormatRaidLootItemLabel = shared.FormatRaidLootItemLabel
local LOOT_ITEM_MENU_PAGE_SIZE = shared.LOOT_ITEM_MENU_PAGE_SIZE
local NormalizeInstanceTuple = shared.NormalizeInstanceTuple
local NormalizeEncounterTuple = shared.NormalizeEncounterTuple
local NormalizeLootInfo = shared.NormalizeLootInfo
local EnsureEncounterJournalLoaded = shared.EnsureEncounterJournalLoaded
local CollectRaidEntries = shared.CollectRaidEntries
local CollectRaidEncounterEntries = shared.CollectRaidEncounterEntries
local CollectRaidLootEntries = shared.CollectRaidLootEntries
local FindRaidEntryByProfile = shared.FindRaidEntryByProfile
local FindRaidLootEntry = shared.FindRaidLootEntry
local RAID_LOOT_DIFFICULTIES = shared.RAID_LOOT_DIFFICULTIES
local EnsureLootLiveBoardMode = shared.EnsureLootLiveBoardMode
local ClampMenuPage = shared.ClampMenuPage
local GetSelectedValuePage = shared.GetSelectedValuePage

local ACTIVATE_PROFILE_REQUIRED_TEXT = "Please go to Profile and activate one Profile first"
local NO_ACTIVE_PROFILE_CURRENT_TEXT = "Current Profile: No profile activated :("
local NO_ACTIVE_PROFILE_TEXT_COLOR = { 1.00, 0.35, 0.25, 1.00 }

local function SetCurrentProfileFont(fontString, text, color)
  if not fontString then
    return
  end
  fontString:SetText(text)
  fontString.__lid_customTextColor = color
  if color and fontString.SetTextColor then
    fontString:SetTextColor(color[1], color[2], color[3], color[4] or 1)
  elseif fontString.SetTextColor then
    fontString:SetTextColor(0.92, 0.96, 1.00, 1.00)
  end
end
local EMPTY_LOOT_LIST_ACCESS = {
  canEditLootList = false,
  canEditManualPoints = false,
  canEditMainAlt = false,
  canEditNotes = false,
}

local function GetLootListContextProfileName()
  local root = RootDB()
  local enabledProfileName = TrimText(GetEnabledLootProfileName() or "")
  if enabledProfileName ~= "" and IsLootProfileVisibleInEditor(root, enabledProfileName) then
    return enabledProfileName
  end
  return nil
end
local GetEditorThemePalette = type(INTERNAL_API.LIDCOUNCIL_GetEditorThemePalette_Impl) == "function" and INTERNAL_API.LIDCOUNCIL_GetEditorThemePalette_Impl or nil
local EnsureLootProfileGroups = shared.EnsureLootProfileGroups
local FindLootProfileGroupIndex = shared.FindLootProfileGroupIndex
local RemoveLootProfileFromGroups = shared.RemoveLootProfileFromGroups
local ToggleLootProfileGroupCollapsed = shared.ToggleLootProfileGroupCollapsed
local GetLootProfileGroupName = shared.GetLootProfileGroupName
local BuildLootProfileNavRows = shared.BuildLootProfileNavRows
local BuildPointRulesText = shared.BuildPointRulesText
local ResolvePointMode = shared.ResolvePointMode
local GetLidTableRows = shared.GetLidTableRows
local BuildLidTableSummaryText = shared.BuildLidTableSummaryText
local POINT_MODE_CHOICES = shared.POINT_MODE_CHOICES
local GetSelectedProfileName = shared.GetSelectedProfileName
local lootListData = INTERNAL_API.LIDCOUNCIL_LootListData_Impl
if type(lootListData) ~= "table" then
  error("LidCouncil missing loot list data helpers.")
end

local lootListRendering = INTERNAL_API.LIDCOUNCIL_LootListRendering_Impl
if type(lootListRendering) ~= "table" then
  error("LidCouncil missing loot list rendering helpers.")
end

local MAX_LOOTLIST_GROUP_NAME = tonumber(lootListData.MAX_LOOTLIST_GROUP_NAME) or 32
local EnsureLootLedgerMetaLocal = lootListData.EnsureLootLedgerMetaLocal
local NormalizeLootLedgerRoleLocal = lootListData.NormalizeLootLedgerRoleLocal
local SetLootLedgerMainAltRole = lootListData.SetLootLedgerMainAltRole
local SetLootLedgerCharacterNote = lootListData.SetLootLedgerCharacterNote
local SetLootLedgerMainCharacter = lootListData.SetLootLedgerMainCharacter
local ClearLootLedgerMainCharacter = lootListData.ClearLootLedgerMainCharacter
local DeleteLootLedgerCharacter = lootListData.DeleteLootLedgerCharacter
local SeedLootLedgerTestRoster = lootListData.SeedLootLedgerTestRoster
local CreateLootListGroup = lootListData.CreateLootListGroup
local DeleteLootListGroup = lootListData.DeleteLootListGroup
local BuildLootLedgerNavRows = lootListData.BuildLootLedgerNavRows
local RefreshLootListPageImpl = lootListRendering.RefreshLootListPage
local BuildLootLedgerHistoryEntries = lootListRendering.BuildLootLedgerHistoryEntries
local GetClassColorForRow = lootListRendering.GetClassColorForRow
local BuildSpecLabel = lootListRendering.BuildSpecLabel
local GetLootLedgerHeaderIconData = lootListRendering.GetLootLedgerHeaderIconData
local ApplyLootLedgerTextureIcon = lootListRendering.ApplyLootLedgerTextureIcon

local NUMERIC_LOOT_LEDGER_SORT_KEYS = {
  sessions = true,
  items = true,
  points = true,
  total = true,
  bis = true,
  offspec = true,
  transmog = true,
  disenchant = true,
}

local VALID_LOOT_LEDGER_SORT_KEYS = {
  spec = true,
  name = true,
  note = true,
  sessions = true,
  items = true,
  points = true,
  total = true,
  bis = true,
  offspec = true,
  transmog = true,
  disenchant = true,
}

local function GetLootListViewMode()
  local root = RootDB()
  root.ui = root.ui or {}
  local mode = TrimText(root.ui.lootLedgerViewMode)
  if mode ~= "DETAILS" then
    mode = "LIST_ONLY"
  end
  root.ui.lootLedgerViewMode = mode
  return mode
end

local function StripButtonTemplateTextures(button)
  if not button then
    return
  end
  if button.__lootListTemplateTexturesStripped then
    return
  end
  button.__lootListTemplateTexturesStripped = true

  if button.SetNormalTexture then pcall(button.SetNormalTexture, button, "") end
  if button.SetHighlightTexture then pcall(button.SetHighlightTexture, button, "") end
  if button.SetPushedTexture then pcall(button.SetPushedTexture, button, "") end
  if button.SetDisabledTexture then pcall(button.SetDisabledTexture, button, "") end

  if type(button.GetRegions) == "function" and type(button.GetNumRegions) == "function" then
    for i = 1, button:GetNumRegions() do
      local region = select(i, button:GetRegions())
      if region and region.GetObjectType and region:GetObjectType() == "Texture" then
        region:SetTexture(nil)
        region:Hide()
      end
    end
  end

  local name = button.GetName and button:GetName() or nil
  if name then
    for _, suffix in ipairs({
      "Left", "Middle", "Right",
      "LeftDisabled", "MiddleDisabled", "RightDisabled",
      "LeftHighlight", "MiddleHighlight", "RightHighlight",
    }) do
      local region = _G[name .. suffix]
      if region and region.Hide then
        region:SetTexture(nil)
        region:Hide()
      end
    end
  end
end

local function ApplyLootListToolbarButtonStyle(button)
  if not button then
    return
  end

  StripButtonTemplateTextures(button)
  if type(button.SetBackdrop) == "function" then
    ApplyFrameSkin(button)
  end

  local palette = GetEditorThemePalette and GetEditorThemePalette() or nil
  local normal = type(palette) == "table" and type(palette.normal) == "table" and palette.normal or { 0.10, 0.10, 0.13, 0.98 }
  local hover = type(palette) == "table" and type(palette.hover) == "table" and palette.hover or { 0.14, 0.14, 0.18, 0.98 }
  local active = type(palette) == "table" and type(palette.active) == "table" and palette.active or { 0.74, 0.22, 0.30, 0.92 }
  local border = type(palette) == "table" and type(palette.border) == "table" and palette.border or { 0.74, 0.22, 0.30, 0.95 }

  button.__lootListToolbarNormal = normal
  button.__lootListToolbarHover = hover
  button.__lootListToolbarActive = active
  if button.SetBackdropBorderColor then
    button:SetBackdropBorderColor(border[1] or 0.74, border[2] or 0.22, border[3] or 0.30, border[4] or 0.95)
  end

  local label = button.GetFontString and button:GetFontString() or nil
  if label and label.SetTextColor then
    label:SetTextColor(0.92, 0.92, 0.96, 1)
  end

  button:SetScript("OnEnter", function(self)
    local color = self.__lootListToolbarSelected and self.__lootListToolbarActive or self.__lootListToolbarHover
    if self.SetBackdropColor then
      self:SetBackdropColor(color[1] or 0.14, color[2] or 0.14, color[3] or 0.18, color[4] or 0.98)
    end
  end)
  button:SetScript("OnLeave", function(self)
    local color = self.__lootListToolbarSelected and self.__lootListToolbarActive or self.__lootListToolbarNormal
    if self.SetBackdropColor then
      self:SetBackdropColor(color[1] or 0.10, color[2] or 0.10, color[3] or 0.13, color[4] or 0.98)
    end
  end)
end

local function SetLootListToolbarButtonSelected(button, selected)
  if not button then
    return
  end
  button.__lootListToolbarSelected = selected and true or false
  local color = button.__lootListToolbarSelected and button.__lootListToolbarActive or button.__lootListToolbarNormal
  if button.SetBackdropColor then
    button:SetBackdropColor(
      color and color[1] or 0.10,
      color and color[2] or 0.10,
      color and color[3] or 0.13,
      color and color[4] or 0.98
    )
  end
end

local function BuildNeedDicePopupSummary(profile, row)
  if type(profile) ~= "table" or type(row) ~= "table" then
    return "Need Dice: None yet"
  end

  local rolls = {}
  local members = type(row.summaryMembers) == "table" and row.summaryMembers or { row.character }
  for _, memberKey in ipairs(members) do
    local ledger = type(profile.lootLedger) == "table" and profile.lootLedger[memberKey] or nil
    for _, item in ipairs(type(ledger) == "table" and ledger.items or {}) do
      local optionKey = string.lower(TrimText(type(item) == "table" and (item.rollOptionKey or item.rollOptionLabel) or ""))
      local rollValue = tonumber(type(item) == "table" and item.rollValue or nil)
      if optionKey == "need" and rollValue then
        rolls[#rolls + 1] = rollValue
      end
    end
  end

  if #rolls == 0 then
    return "Need Dice: None yet"
  end

  table.sort(rolls, function(a, b)
    return (tonumber(a) or 0) > (tonumber(b) or 0)
  end)

  local highest = tonumber(rolls[1]) or 0
  local total = 0
  local recent = {}
  for index, value in ipairs(rolls) do
    total = total + (tonumber(value) or 0)
    if index <= 8 then
      recent[#recent + 1] = tostring(value)
    end
  end

  return string.format(
    "Need Dice: %d roll(s) | avg %.1f | high %d | recent [%s]",
    #rolls,
    total / #rolls,
    highest,
    table.concat(recent, ", ")
  )
end

local CreateLootListDetailsPopupHelpers = INTERNAL_API.LIDCOUNCIL_CreateLootListDetailsPopupHelpers_Impl
if type(CreateLootListDetailsPopupHelpers) ~= "function" then
  error("LidCouncil missing loot list details popup helpers.")
end

local lootListDetailsPopupHelpers = CreateLootListDetailsPopupHelpers({
  ApplyFrameSkin = ApplyFrameSkin,
  ApplyLootListToolbarButtonStyle = ApplyLootListToolbarButtonStyle,
  GetLootListViewMode = GetLootListViewMode,
})

local CreateLootListAwardsViewHelpers = INTERNAL_API.LIDCOUNCIL_CreateLootListAwardsViewHelpers_Impl
if type(CreateLootListAwardsViewHelpers) ~= "function" then
  error("LidCouncil missing loot list awards view helpers.")
end

local lootListAwardsViewHelpers = CreateLootListAwardsViewHelpers({
  ApplyFrameSkin = ApplyFrameSkin,
  ApplyLootListToolbarButtonStyle = ApplyLootListToolbarButtonStyle,
  BindMouseWheelScroll = BindMouseWheelScroll,
  TrimText = TrimText,
  ResolveOptionalApiFunction = ResolveOptionalApiFunction,
  FormatDateTime = FormatDateTime,
})

local CreateLootListRecommendationsViewHelpers = INTERNAL_API.LIDCOUNCIL_CreateLootListRecommendationsViewHelpers_Impl
if type(CreateLootListRecommendationsViewHelpers) ~= "function" then
  error("LidCouncil missing loot list recommendations view helpers.")
end

local lootListRecommendationsViewHelpers = CreateLootListRecommendationsViewHelpers({
  ApplyFrameSkin = ApplyFrameSkin,
  ApplyLootListToolbarButtonStyle = ApplyLootListToolbarButtonStyle,
  BindMouseWheelScroll = BindMouseWheelScroll,
  CreateCustomDropdownControl = CreateCustomDropdownControl,
  CollectRaidEntries = CollectRaidEntries,
  CollectRaidEncounterEntries = CollectRaidEncounterEntries,
  FindRaidEntryByProfile = FindRaidEntryByProfile,
  CollectRaidLootEntries = CollectRaidLootEntries,
  RAID_LOOT_DIFFICULTIES = RAID_LOOT_DIFFICULTIES,
  FormatRaidLootItemLabel = FormatRaidLootItemLabel,
  ResolveRollOptionIcon = ResolveRollOptionIcon,
  GetLootProfile = GetLootProfile,
  TrimText = TrimText,
  ResolveOptionalApiFunction = ResolveOptionalApiFunction,
})

local function BuildLootListPage(editor, page)
  if not editor or not page then return end

  local navBg, rightBg = CreateSectionShell(page, 432)
  editor.lootListNavBg = navBg
  editor.lootListRightBg = rightBg

  local inactiveOverlay = CreateFrame("Frame", nil, page, "BackdropTemplate")
  ApplyFrameSkin(inactiveOverlay)
  inactiveOverlay:SetPoint("TOPLEFT", page, "TOPLEFT", 0, -44)
  inactiveOverlay:SetPoint("BOTTOMRIGHT", page, "BOTTOMRIGHT", 0, 0)
  inactiveOverlay:EnableMouse(true)
  inactiveOverlay:SetFrameStrata("HIGH")
  inactiveOverlay:SetFrameLevel((page.GetFrameLevel and page:GetFrameLevel() or 0) + 20)
  inactiveOverlay:Hide()
  editor.lootListInactiveOverlay = inactiveOverlay

  local inactiveText = inactiveOverlay:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
  inactiveText:SetPoint("CENTER", 0, 0)
  inactiveText:SetWidth(520)
  inactiveText:SetJustifyH("CENTER")
  inactiveText:SetJustifyV("MIDDLE")
  inactiveText:SetText(ACTIVATE_PROFILE_REQUIRED_TEXT)
  editor.lootListInactiveText = inactiveText

  local navTitle = navBg:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
  navTitle:SetPoint("TOPLEFT", 8, -8)
  navTitle:SetText("Loot List")
  editor.lootLedgerNavTitle = navTitle

  local recommendationsBtn = CreateFrame("Button", nil, navBg, "UIPanelButtonTemplate,BackdropTemplate")
  recommendationsBtn:SetSize(118, 22)
  recommendationsBtn:SetPoint("TOPLEFT", navBg, "TOPLEFT", 86, -5)
  recommendationsBtn:SetText("Personal Recs")
  ApplyLootListToolbarButtonStyle(recommendationsBtn)
  editor.lootLedgerRecommendationsBtn = recommendationsBtn

  local seedTestBtn = CreateFrame("Button", nil, navBg, "UIPanelButtonTemplate,BackdropTemplate")
  seedTestBtn:SetSize(126, 22)
  seedTestBtn:SetPoint("TOPRIGHT", -8, -30)
  seedTestBtn:SetText("Seed Test Raiders")
  ApplyLootListToolbarButtonStyle(seedTestBtn)
  seedTestBtn:Hide()
  editor.lootLedgerSeedTestBtn = seedTestBtn

  local modeListBtn = CreateFrame("Button", nil, navBg, "UIPanelButtonTemplate,BackdropTemplate")
  modeListBtn:SetSize(104, 22)
  modeListBtn:SetText("Pop Out Mode")
  ApplyLootListToolbarButtonStyle(modeListBtn)
  editor.lootLedgerModeListBtn = modeListBtn

  local modeDetailsBtn = CreateFrame("Button", nil, navBg, "UIPanelButtonTemplate,BackdropTemplate")
  modeDetailsBtn:SetSize(82, 22)
  modeDetailsBtn:SetPoint("RIGHT", seedTestBtn, "LEFT", -8, 0)
  modeDetailsBtn:SetText("Split Mode")
  ApplyLootListToolbarButtonStyle(modeDetailsBtn)
  editor.lootLedgerModeDetailsBtn = modeDetailsBtn

  local modeAwardsBtn = CreateFrame("Button", nil, navBg, "UIPanelButtonTemplate,BackdropTemplate")
  modeAwardsBtn:SetSize(86, 22)
  modeAwardsBtn:SetText("Fun Awards")
  ApplyLootListToolbarButtonStyle(modeAwardsBtn)
  editor.lootLedgerModeAwardsBtn = modeAwardsBtn
  modeListBtn:SetPoint("RIGHT", modeDetailsBtn, "LEFT", -8, 0)

  local function UpdateLootListToolbarLayout()
    if not editor then
      return
    end
    local anchor = editor.lootLedgerSeedTestBtn
    local modeAwards = editor.lootLedgerModeAwardsBtn
    local modeDetails = editor.lootLedgerModeDetailsBtn
    local modeList = editor.lootLedgerModeListBtn
    if not modeAwards or not modeDetails or not modeList or not navBg then
      return
    end

    modeAwards:ClearAllPoints()
    if anchor and anchor.IsShown and anchor:IsShown() then
      modeAwards:SetPoint("RIGHT", anchor, "LEFT", -8, 0)
    else
      modeAwards:SetPoint("TOPRIGHT", navBg, "TOPRIGHT", -8, -30)
    end

    modeDetails:ClearAllPoints()
    modeDetails:SetPoint("RIGHT", modeAwards, "LEFT", -8, 0)

    modeList:ClearAllPoints()
    modeList:SetPoint("RIGHT", modeDetails, "LEFT", -8, 0)
  end
  editor.UpdateLootListToolbarLayout = UpdateLootListToolbarLayout
  UpdateLootListToolbarLayout()

  local function UpdateLootListModeButtons()
    local mode = GetLootListViewMode()
    local listOnly = mode == "LIST_ONLY"
    local detailsMode = mode == "DETAILS"
    local awardsOpen = lootListAwardsViewHelpers.IsLootListAwardsPopupShown and lootListAwardsViewHelpers.IsLootListAwardsPopupShown(editor)
    local recommendationsOpen = lootListRecommendationsViewHelpers.IsLootListRecommendationsPopupShown
      and lootListRecommendationsViewHelpers.IsLootListRecommendationsPopupShown(editor)
    if editor.lootLedgerModeListBtn then
      ApplyLootListToolbarButtonStyle(editor.lootLedgerModeListBtn)
      SetTextListButtonTextColor(editor.lootLedgerModeListBtn, listOnly and { 1.00, 0.94, 0.62, 1.00 } or { 0.82, 0.82, 0.86, 1.00 })
      SetLootListToolbarButtonSelected(editor.lootLedgerModeListBtn, listOnly)
    end
    if editor.lootLedgerModeDetailsBtn then
      ApplyLootListToolbarButtonStyle(editor.lootLedgerModeDetailsBtn)
      SetTextListButtonTextColor(editor.lootLedgerModeDetailsBtn, detailsMode and { 1.00, 0.94, 0.62, 1.00 } or { 0.82, 0.82, 0.86, 1.00 })
      SetLootListToolbarButtonSelected(editor.lootLedgerModeDetailsBtn, detailsMode)
    end
    if editor.lootLedgerModeAwardsBtn then
      ApplyLootListToolbarButtonStyle(editor.lootLedgerModeAwardsBtn)
      SetTextListButtonTextColor(editor.lootLedgerModeAwardsBtn, awardsOpen and { 1.00, 0.94, 0.62, 1.00 } or { 0.82, 0.82, 0.86, 1.00 })
      SetLootListToolbarButtonSelected(editor.lootLedgerModeAwardsBtn, awardsOpen)
    end
    if editor.lootLedgerRecommendationsBtn then
      ApplyLootListToolbarButtonStyle(editor.lootLedgerRecommendationsBtn)
      SetTextListButtonTextColor(editor.lootLedgerRecommendationsBtn, recommendationsOpen and { 1.00, 0.94, 0.62, 1.00 } or { 0.82, 0.82, 0.86, 1.00 })
      SetLootListToolbarButtonSelected(editor.lootLedgerRecommendationsBtn, recommendationsOpen)
    end
  end
  editor.UpdateLootListModeButtons = UpdateLootListModeButtons
  UpdateLootListModeButtons()
  editor.OpenLootLedgerDetailsPopup = function(self, row)
    lootListDetailsPopupHelpers.OpenLootListDetailsPopup(self, row)
  end
  editor.OpenLootLedgerAwardsPopup = function(self, profileName)
    lootListAwardsViewHelpers.OpenLootListAwardsPopup(self, profileName)
  end
  editor.OpenLootLedgerRecommendationsPopup = function(self, profileName)
    lootListRecommendationsViewHelpers.OpenLootListRecommendationsPopup(self, profileName)
  end

  recommendationsBtn:SetScript("OnClick", function()
    local profileName = GetEnabledLootProfileName()
    if TrimText(profileName) == "" then
      return
    end
    lootListRecommendationsViewHelpers.OpenLootListRecommendationsPopup(editor, profileName)
  end)

  local searchLabel = navBg:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  searchLabel:SetPoint("TOPLEFT", 8, -60)
  searchLabel:SetText("Search:")
  editor.lootLedgerSearchLabel = searchLabel

  local searchEdit = CreateSimpleEditBox(navBg, 214, 22)
  searchEdit:SetPoint("LEFT", searchLabel, "RIGHT", 8, 0)
  editor.lootLedgerSearchEdit = searchEdit

  local headerRow = CreateFrame("Frame", nil, navBg)
  headerRow:SetPoint("TOPLEFT", 8, -88)
  headerRow:SetSize(394, 18)
  editor.lootLedgerListHeader = headerRow

  local function GetLootLedgerSortState()
    local root = RootDB()
    root.ui = root.ui or {}
    local sortKey = TrimText(root.ui.lootLedgerSortKey)
    if VALID_LOOT_LEDGER_SORT_KEYS[sortKey] ~= true then
      sortKey = "name"
    end
    local descending = root.ui.lootLedgerSortDescending
    if type(descending) ~= "boolean" then
      descending = NUMERIC_LOOT_LEDGER_SORT_KEYS[sortKey] == true
    end
    root.ui.lootLedgerSortKey = sortKey
    root.ui.lootLedgerSortDescending = descending
    editor.__lootLedgerSortKey = sortKey
    editor.__lootLedgerSortDescending = descending
    return sortKey, descending
  end

  local function SetHeaderLabelColor(button, color)
    local label = button and button.__labelText or nil
    local resolved = type(color) == "table" and color or nil
    if label and label.SetTextColor then
      label:SetTextColor(
        tonumber(resolved and resolved[1]) or 0.86,
        tonumber(resolved and resolved[2]) or 0.86,
        tonumber(resolved and resolved[3]) or 0.90,
        tonumber(resolved and resolved[4]) or 1
      )
    end
  end

  local function UpdateLootLedgerSortHeaderState(self)
    local sortKey, descending = GetLootLedgerSortState()
    for _, button in ipairs((self and self.__lootLedgerSortHeaders) or {}) do
      local isSelected = button.__sortKey == sortKey
      local suffix = isSelected and (descending and " v" or " ^") or ""
      if button.__labelText then
        button.__labelText:SetText(tostring(button.__baseLabel or "") .. suffix)
      end
      if button.__baseBg then
        button.__baseBg:SetVertexColor(0.08, 0.06, 0.08, 0.82)
      end
      if button.__selectionBg then
        button.__selectionBg:SetVertexColor(0, 0, 0, 0)
      end
      if button.__selectionAccent then
        button.__selectionAccent:SetVertexColor(0, 0, 0, 0)
      end
      if button.SetButtonState then
        button:SetButtonState("NORMAL", false)
      end
      SetHeaderLabelColor(button, { 0.86, 0.86, 0.90, 1.00 })
    end
  end

  local function ApplyLootLedgerSort(sortKey)
    local currentKey, currentDescending = GetLootLedgerSortState()
    local root = RootDB()
    root.ui = root.ui or {}
    local nextDescending
    if currentKey == sortKey then
      nextDescending = not currentDescending
    else
      nextDescending = NUMERIC_LOOT_LEDGER_SORT_KEYS[sortKey] == true
    end
    root.ui.lootLedgerSortKey = sortKey
    root.ui.lootLedgerSortDescending = nextDescending
    editor.__lootLedgerSortKey = sortKey
    editor.__lootLedgerSortDescending = nextDescending
    UpdateLootLedgerSortHeaderState(editor)
    if editor.Refresh then
      editor:Refresh()
    end
  end

  local function MakeHeaderText(parent, label, x, width, sortKey, tooltipText)
    if sortKey then
      local button = CreateFrame("Button", nil, parent)
      button:SetPoint("TOPLEFT", x, 0)
      button:SetSize(width, 18)
      button:RegisterForClicks("LeftButtonUp")

      local bg = button:CreateTexture(nil, "BACKGROUND")
      bg:SetAllPoints(true)
      bg:SetTexture("Interface\\Buttons\\WHITE8x8")
      bg:SetVertexColor(0.08, 0.06, 0.08, 0.82)
      button.__baseBg = bg

      local hover = button:CreateTexture(nil, "HIGHLIGHT")
      hover:SetAllPoints(true)
      hover:SetTexture("Interface\\Buttons\\WHITE8x8")
      do
        local themePalette = GetEditorThemePalette and GetEditorThemePalette() or nil
        local active = type(themePalette) == "table" and themePalette.active or { 1.00, 0.88, 0.32, 0.92 }
        hover:SetVertexColor(active[1] or 1.00, active[2] or 0.88, active[3] or 0.32, 0.10)
      end
      button.__hoverBg = hover

      local text = button:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
      text:SetPoint("TOPLEFT", 0, 0)
      text:SetPoint("BOTTOMRIGHT", 0, 0)
      text:SetJustifyH("LEFT")
      text:SetText(label)
      button.__labelText = text
      button.__baseLabel = label
      button.__sortKey = sortKey
      button.__tooltipText = tooltipText
      button:SetScript("OnClick", function()
        ApplyLootLedgerSort(sortKey)
      end)
      button:SetScript("OnEnter", function(self)
        local tip = type(self.__tooltipText) == "string" and self.__tooltipText or ""
        if tip == "" or type(GameTooltip) ~= "table" then
          return
        end
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        GameTooltip:SetText(tip, 1.00, 0.92, 0.35, 1.00, true)
        GameTooltip:Show()
      end)
      button:SetScript("OnLeave", function()
        if type(GameTooltip) == "table" then
          GameTooltip:Hide()
        end
      end)
      return button
    end

    local text = parent:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    text:SetPoint("TOPLEFT", x, 0)
    text:SetWidth(width)
    text:SetJustifyH("LEFT")
    text:SetText(label)
    return text
  end

  editor.lootLedgerHeaderSpec = MakeHeaderText(headerRow, "Spec", 22, 52, "spec")
  editor.lootLedgerHeaderName = MakeHeaderText(headerRow, "Character-Realm", 78, 164, "name")
  editor.lootLedgerHeaderNote = MakeHeaderText(headerRow, "Note", 246, 96, "note")
  editor.lootLedgerHeaderSessions = MakeHeaderText(headerRow, "Sess", 244, 40, "sessions", "Joined Sessions")
  editor.lootLedgerHeaderItems = MakeHeaderText(headerRow, "Items", 288, 40, "items", "Received items")
  editor.lootLedgerHeaderOffSpec = MakeHeaderText(headerRow, "OS", 332, 30, "offspec", "Off-Spec")
  editor.lootLedgerHeaderTransmog = MakeHeaderText(headerRow, "TM", 366, 30, "transmog", "Transmog")
  editor.lootLedgerHeaderDisenchant = MakeHeaderText(headerRow, "DE", 400, 30, "disenchant", "Disenchant")
  editor.lootLedgerHeaderPoints = MakeHeaderText(headerRow, "Points", 434, 42, "points", "Character Points")
  editor.lootLedgerHeaderBis = MakeHeaderText(headerRow, "BiS", 480, 30, "bis", "Best in Slot")
  editor.lootLedgerHeaderTotal = MakeHeaderText(headerRow, "Total", 514, 40, "total", "Total Points")
  editor.__lootLedgerSortHeaders = {
    editor.lootLedgerHeaderSpec,
    editor.lootLedgerHeaderName,
    editor.lootLedgerHeaderNote,
    editor.lootLedgerHeaderSessions,
    editor.lootLedgerHeaderItems,
    editor.lootLedgerHeaderOffSpec,
    editor.lootLedgerHeaderTransmog,
    editor.lootLedgerHeaderDisenchant,
    editor.lootLedgerHeaderPoints,
    editor.lootLedgerHeaderBis,
    editor.lootLedgerHeaderTotal,
  }
  editor.UpdateLootLedgerSortHeaderState = UpdateLootLedgerSortHeaderState
  UpdateLootLedgerSortHeaderState(editor)

  local charScroll = CreateFrame("ScrollFrame", nil, navBg, "UIPanelScrollFrameTemplate")
  charScroll:SetPoint("TOPLEFT", 8, -110)
  charScroll:SetPoint("BOTTOMRIGHT", -26, 30)
  BindMouseWheelScroll(charScroll, 18)
  editor.lootLedgerCharScroll = charScroll

  local charContent = CreateFrame("Frame", nil, charScroll)
  charContent:SetSize(394, 1)
  charScroll:SetScrollChild(charContent)
  editor.lootLedgerCharContent = charContent
  editor.lootLedgerCharacterRows = {}

  local addGroupBtn = CreateFrame("Button", nil, navBg, "UIPanelButtonTemplate")
  addGroupBtn:SetSize(118, 22)
  addGroupBtn:SetPoint("BOTTOMLEFT", 8, 6)
  addGroupBtn:SetText("Add Group")
  addGroupBtn:Hide()
  editor.lootLedgerAddGroupBtn = addGroupBtn

  local deleteGroupBtn = CreateFrame("Button", nil, navBg, "UIPanelButtonTemplate")
  deleteGroupBtn:SetSize(118, 22)
  deleteGroupBtn:SetPoint("LEFT", addGroupBtn, "RIGHT", 8, 0)
  deleteGroupBtn:SetText("Delete Group")
  deleteGroupBtn:Hide()
  editor.lootLedgerDeleteGroupBtn = deleteGroupBtn

  local dragHint = navBg:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  dragHint:SetPoint("BOTTOMLEFT", 8, 6)
  dragHint:SetWidth(394)
  dragHint:SetJustifyH("LEFT")
  dragHint:SetText("Select a character to review details and manage Main / Alt links.")
  editor.lootLedgerDragHint = dragHint

  local rightScroll = CreateFrame("ScrollFrame", nil, rightBg, "UIPanelScrollFrameTemplate")
  rightScroll:SetPoint("TOPLEFT", 6, -6)
  rightScroll:SetPoint("BOTTOMRIGHT", -28, 6)
  BindMouseWheelScroll(rightScroll, 18)
  editor.lootLedgerRightScroll = rightScroll

  local rightContent = CreateFrame("Frame", nil, rightScroll)
  rightContent:SetSize(560, 1)
  rightScroll:SetScrollChild(rightContent)
  editor.lootLedgerRightContent = rightContent

  local title = rightContent:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
  title:SetPoint("TOPLEFT", 18, -16)
  title:SetText("Loot List Details")
  editor.lootListTitle = title

  local heroFrame = CreateFrame("Frame", nil, rightContent, "BackdropTemplate")
  heroFrame:SetPoint("TOPLEFT", 18, -46)
  heroFrame:SetSize(552, 88)
  ApplyFrameSkin(heroFrame)
  editor.lootLedgerHeroFrame = heroFrame

  local heroIcon = heroFrame:CreateTexture(nil, "ARTWORK")
  heroIcon:SetSize(34, 34)
  heroIcon:SetPoint("TOPLEFT", 14, -14)
  heroIcon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
  editor.lootLedgerHeroIcon = heroIcon

  local selectedLabel = heroFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
  selectedLabel:SetPoint("TOPLEFT", heroIcon, "TOPRIGHT", 12, -2)
  selectedLabel:SetPoint("RIGHT", -14, 0)
  selectedLabel:SetJustifyH("LEFT")
  if selectedLabel.SetMaxLines then
    selectedLabel:SetMaxLines(1)
  end
  selectedLabel:SetText("(no character selected)")
  editor.lootLedgerSelectedLabel = selectedLabel

  local totalLabel = heroFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  totalLabel:SetPoint("TOPLEFT", selectedLabel, "BOTTOMLEFT", 0, -6)
  totalLabel:SetPoint("RIGHT", -14, 0)
  totalLabel:SetJustifyH("LEFT")
  if totalLabel.SetMaxLines then
    totalLabel:SetMaxLines(1)
  end
  totalLabel:SetText("Class / Spec")
  editor.lootLedgerTotalLabel = totalLabel

  local summaryText = heroFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  summaryText:SetPoint("TOPLEFT", totalLabel, "BOTTOMLEFT", 0, -8)
  summaryText:SetPoint("RIGHT", -14, 0)
  summaryText:SetJustifyH("LEFT")
  summaryText:SetText("")
  editor.lootLedgerSummaryText = summaryText

  local statCards = {}
  local statLabels = {
    { key = "sessions", title = "Sessions Joined" },
    { key = "items", title = "Items Received" },
    { key = "points", title = "Character Points" },
    { key = "total", title = "Total" },
    { key = "bis", title = "BiS" },
    { key = "offspec", title = "Off-Spec" },
    { key = "transmog", title = "Transmog" },
    { key = "disenchant", title = "Disenchant" },
  }
  for index, info in ipairs(statLabels) do
    local card = CreateFrame("Frame", nil, rightContent, "BackdropTemplate")
    card:SetSize(128, 54)
    ApplyFrameSkin(card)

    local valueText = card:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    valueText:SetPoint("TOPLEFT", 10, -8)
    valueText:SetJustifyH("LEFT")
    valueText:SetText("0")

    local titleText = card:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    titleText:SetPoint("TOPLEFT", valueText, "BOTTOMLEFT", 0, -4)
    titleText:SetPoint("RIGHT", -8, 0)
    titleText:SetJustifyH("LEFT")
    titleText:SetText(info.title)

    statCards[info.key] = {
      frame = card,
      value = valueText,
      title = titleText,
    }
  end
  editor.lootLedgerStatCards = statCards

  local membersDivider = CreateSectionDivider(rightContent)
  editor.lootLedgerMembersDivider = membersDivider

  local membersHeader = MakeYellowSubHeader(rightContent, "Main and Alt", 18, -150)
  editor.lootLedgerMembersHeader = membersHeader

  local roleLabel = rightContent:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  roleLabel:SetPoint("TOPLEFT", 18, -176)
  roleLabel:SetText("Role:")
  editor.lootLedgerRoleLabel = roleLabel

  local roleDropdown = nil
  if type(CreateCustomDropdownControl) == "function" then
    roleDropdown = CreateCustomDropdownControl(editor, rightContent, {
      width = 120,
      text = "Main",
    })
    roleDropdown:SetPoint("LEFT", roleLabel, "RIGHT", 8, 0)
  else
    roleDropdown = CreateSimpleEditBox(rightContent, 120, 22)
    roleDropdown:SetPoint("LEFT", roleLabel, "RIGHT", 8, 0)
  end
  editor.lootLedgerRoleDropdown = roleDropdown

  local noteLabel = rightContent:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  noteLabel:SetPoint("TOPLEFT", 18, -206)
  noteLabel:SetText("Note:")
  editor.lootLedgerCharacterNoteLabel = noteLabel

  local characterNoteEdit = CreateSimpleEditBox(rightContent, 360, 22)
  characterNoteEdit:SetPoint("LEFT", noteLabel, "RIGHT", 8, 0)
  editor.lootLedgerCharacterNoteEdit = characterNoteEdit

  local mainLabel = rightContent:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  mainLabel:SetPoint("TOPLEFT", 18, -236)
  mainLabel:SetText("Main:")
  editor.lootLedgerMainLabel = mainLabel

  local summaryDropdown = nil
  if type(CreateCustomDropdownControl) == "function" then
    summaryDropdown = CreateCustomDropdownControl(editor, rightContent, {
      width = 280,
      text = "(select main)",
    })
    summaryDropdown:SetPoint("LEFT", mainLabel, "RIGHT", 8, 0)
  else
    summaryDropdown = CreateSimpleEditBox(rightContent, 280, 22)
    summaryDropdown:SetPoint("LEFT", mainLabel, "RIGHT", 8, 0)
  end
  editor.lootLedgerSummaryDropdown = summaryDropdown

  local linkSummaryBtn = CreateFrame("Button", nil, rightContent, "UIPanelButtonTemplate")
  linkSummaryBtn:SetSize(96, 22)
  linkSummaryBtn:SetPoint("LEFT", roleDropdown, "RIGHT", 10, 0)
  linkSummaryBtn:SetText("Apply")
  editor.lootLedgerSummaryLinkBtn = linkSummaryBtn

  local clearSummaryBtn = CreateFrame("Button", nil, rightContent, "UIPanelButtonTemplate")
  clearSummaryBtn:SetSize(110, 22)
  clearSummaryBtn:SetPoint("LEFT", linkSummaryBtn, "RIGHT", 8, 0)
  clearSummaryBtn:SetText("Make Main")
  editor.lootLedgerSummaryClearBtn = clearSummaryBtn

  local membersRowsFrame = CreateFrame("Frame", nil, rightContent)
  membersRowsFrame:SetPoint("TOPLEFT", 18, -266)
  membersRowsFrame:SetSize(552, 1)
  editor.lootLedgerMembersRowsFrame = membersRowsFrame
  editor.lootLedgerMembersRows = {}

  local membersText = rightContent:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  membersText:SetPoint("TOPLEFT", membersRowsFrame, "BOTTOMLEFT", 0, -8)
  membersText:SetWidth(560)
  membersText:SetJustifyH("LEFT")
  membersText:SetText("")
  editor.lootLedgerMembersText = membersText

  local historyDivider = CreateSectionDivider(rightContent)
  editor.lootLedgerHistoryDivider = historyDivider

  local historyHeader = MakeYellowSubHeader(rightContent, "Loot History", 18, -280)
  editor.lootLedgerHistoryHeader = historyHeader

  local historyColumns = CreateFrame("Frame", nil, rightContent)
  historyColumns:SetPoint("TOPLEFT", 18, -304)
  historyColumns:SetSize(552, 18)
  editor.lootLedgerHistoryColumns = historyColumns

  editor.lootLedgerHistoryItemHeader = MakeHeaderText(historyColumns, "Item", 0, 286)
  editor.lootLedgerHistoryReceivedHeader = MakeHeaderText(historyColumns, "Received", 300, 160)
  editor.lootLedgerHistoryPointsHeader = MakeHeaderText(historyColumns, "Points", 468, 60)

  local historyRowsFrame = CreateFrame("Frame", nil, rightContent)
  historyRowsFrame:SetPoint("TOPLEFT", 18, -326)
  historyRowsFrame:SetSize(552, 1)
  editor.lootLedgerHistoryRowsFrame = historyRowsFrame
  editor.lootLedgerHistoryRows = {}

  local historyText = rightContent:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  historyText:SetPoint("TOPLEFT", historyRowsFrame, "BOTTOMLEFT", 0, -8)
  historyText:SetWidth(560)
  historyText:SetJustifyH("LEFT")
  historyText:SetText("")
  editor.lootLedgerHistoryText = historyText

  local manualDivider = CreateSectionDivider(rightContent)
  editor.lootLedgerManualDivider = manualDivider

  local addHeader = MakeYellowSubHeader(rightContent, "Add Manual Points", 18, -304)
  editor.lootLedgerHeader = addHeader

  local function MakeFieldLabel(parent, label)
    local text = parent:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    text:SetJustifyH("LEFT")
    text:SetText(label)
    return text
  end

  local characterEditLabel = MakeFieldLabel(rightContent, "Character-Realm")
  editor.lootLedgerCharacterEditLabel = characterEditLabel

  local characterEdit = CreateSimpleEditBox(rightContent, 180, 22)
  characterEdit:SetPoint("TOPLEFT", 18, -304)
  characterEditLabel:Hide()
  characterEdit:Hide()
  editor.lootLedgerCharacterEdit = characterEdit

  local itemEditLabel = MakeFieldLabel(rightContent, "Comment")
  editor.lootLedgerItemEditLabel = itemEditLabel

  local itemEdit = CreateSimpleEditBox(rightContent, 260, 22)
  itemEdit:SetPoint("TOPLEFT", 18, -304)
  editor.lootLedgerItemEdit = itemEdit

  local pointsEditLabel = MakeFieldLabel(rightContent, "Points")
  editor.lootLedgerPointsEditLabel = pointsEditLabel

  local pointsEdit = CreateSimpleEditBox(rightContent, 70, 22)
  pointsEdit:SetPoint("LEFT", itemEdit, "RIGHT", 10, 0)
  editor.lootLedgerPointsEdit = pointsEdit

  local function SanitizeManualPointsText(value)
    local text = tostring(value or "")
    local sign = ""
    if text:sub(1, 1) == "-" then
      sign = "-"
    end
    text = text:gsub("[^%d]", "")
    if text == "" then
      return sign
    end
    return sign .. text
  end

  pointsEdit:SetScript("OnTextChanged", function(self, userInput)
    if not userInput or self.__suppressManualSanitize then
      return
    end
    local current = self:GetText() or ""
    local sanitized = SanitizeManualPointsText(current)
    if sanitized ~= current then
      self.__suppressManualSanitize = true
      self:SetText(sanitized)
      self:SetCursorPosition(#sanitized)
      self.__suppressManualSanitize = nil
    end
  end)

  local addBtn = CreateFrame("Button", nil, rightContent, "UIPanelButtonTemplate")
  addBtn:SetSize(150, 22)
  addBtn:SetPoint("TOPLEFT", 18, -336)
  addBtn:SetText("Add Manual Points")
  editor.lootLedgerAddEntryBtn = addBtn

  local deleteManualBtn = CreateFrame("Button", nil, rightContent, "UIPanelButtonTemplate")
  deleteManualBtn:SetSize(170, 22)
  deleteManualBtn:SetPoint("LEFT", addBtn, "RIGHT", 10, 0)
  deleteManualBtn:SetText("Delete Manual Entry")
  editor.lootLedgerDeleteEntryBtn = deleteManualBtn

  local deleteCharacterBtn = CreateFrame("Button", nil, rightContent, "UIPanelButtonTemplate")
  deleteCharacterBtn:SetSize(150, 22)
  deleteCharacterBtn:SetText("Delete Character")
  editor.lootLedgerDeleteCharacterBtn = deleteCharacterBtn

  local feedback = rightContent:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  feedback:SetPoint("TOPLEFT", addBtn, "BOTTOMLEFT", 0, -8)
  feedback:SetWidth(560)
  feedback:SetJustifyH("LEFT")
  feedback:SetText("")
  editor.lootLedgerFeedback = feedback

  page.__contentHeight = 1

  local function EnsureLootListStaticPopups()
    if type(StaticPopupDialogs) ~= "table" then
      return
    end

    if not StaticPopupDialogs.LIDCOUNCIL_CREATE_LEDGER_GROUP then
      StaticPopupDialogs.LIDCOUNCIL_CREATE_LEDGER_GROUP = {
        text = "Create new Loot List group:",
        button1 = ACCEPT,
        button2 = CANCEL,
        hasEditBox = 1,
        maxLetters = MAX_LOOTLIST_GROUP_NAME,
        timeout = 0,
        whileDead = 1,
        hideOnEscape = 1,
        preferredIndex = 3,
        OnShow = function(self)
          if self.editBox then
            self.editBox:SetText("")
            self.editBox:SetFocus()
          end
        end,
        EditBoxOnEnterPressed = function(self)
          local parent = self:GetParent()
          if parent and parent.button1 then
            parent.button1:Click()
          end
        end,
        OnAccept = function(self)
          local _, profileName = GetLootProfile(GetLootListContextProfileName())
          if not GetLootProfileAccessInfo(profileName).canEditLootList then
            if editor.lootLedgerDragHint then
              editor.lootLedgerDragHint:SetText("Raiders can view the Loot List, but cannot modify it.")
            end
            return
          end
          local profile = GetLootProfile(GetLootListContextProfileName())
          local ok, result = CreateLootListGroup(profile, self.editBox and self.editBox:GetText() or "")
          if ok then
            editor.selectedLootLedgerType = "group"
            editor.selectedLootLedgerKey = tostring(result or "")
            if editor.lootLedgerDragHint then
              editor.lootLedgerDragHint:SetText("Created group: " .. tostring(result or ""))
            end
            if editor.Refresh then editor:Refresh() end
          elseif editor.lootLedgerDragHint then
            editor.lootLedgerDragHint:SetText(tostring(result or "Could not create Loot List group."))
          end
        end,
      }
    end

    if not StaticPopupDialogs.LIDCOUNCIL_DELETE_LEDGER_GROUP then
      StaticPopupDialogs.LIDCOUNCIL_DELETE_LEDGER_GROUP = {
        text = "Delete the Loot List group \"%s\"?\nCharacters inside the group will remain and become ungrouped.",
        button1 = ACCEPT,
        button2 = CANCEL,
        timeout = 0,
        whileDead = 1,
        hideOnEscape = 1,
        preferredIndex = 3,
        OnAccept = function(_, data)
          local _, profileName = GetLootProfile(GetLootListContextProfileName())
          if not GetLootProfileAccessInfo(profileName).canEditLootList then
            if editor.lootLedgerDragHint then
              editor.lootLedgerDragHint:SetText("Raiders can view the Loot List, but cannot modify it.")
            end
            return
          end
          local groupName = type(data) == "table" and data.groupName or nil
          local profile = GetLootProfile(GetLootListContextProfileName())
          local ok, result = DeleteLootListGroup(profile, groupName)
          if ok then
            editor.selectedLootLedgerType = "character"
            editor.selectedLootLedgerKey = nil
            if editor.lootLedgerDragHint then
              editor.lootLedgerDragHint:SetText("Deleted group: " .. tostring(groupName or ""))
            end
            if editor.Refresh then editor:Refresh() end
          elseif editor.lootLedgerDragHint then
            editor.lootLedgerDragHint:SetText(tostring(result or "Could not delete Loot List group."))
          end
        end,
      }
    end

    if not StaticPopupDialogs.LIDCOUNCIL_DELETE_LOOT_LEDGER_CHARACTER then
      StaticPopupDialogs.LIDCOUNCIL_DELETE_LOOT_LEDGER_CHARACTER = {
        text = "Are you sure you want to delete this character and points?",
        button1 = "Yes",
        button2 = "No",
        timeout = 0,
        whileDead = 1,
        hideOnEscape = 1,
        preferredIndex = 3,
        OnAccept = function()
          local profileName = GetLootListContextProfileName()
          local characterKey = TrimText(editor.selectedLootLedgerCharacter)
          if characterKey == "" then
            feedback:SetText("Select a character first.")
            return
          end

          local requestDelete = type(ResolveOptionalApiFunction) == "function"
            and ResolveOptionalApiFunction("LIDCOUNCIL_RequestLootLedgerCharacterDeleteFlow")
            or nil
          local ok, result, flowMode
          if type(requestDelete) == "function" then
            ok, result, flowMode = requestDelete(profileName, characterKey)
          else
            local profile = GetLootProfile(profileName)
            ok, result = DeleteLootLedgerCharacter(profile, characterKey)
            flowMode = "LOCAL"
          end

          if ok then
            editor.selectedLootLedgerType = "none"
            editor.selectedLootLedgerKey = nil
            editor.selectedLootLedgerCharacter = nil
            editor.selectedLootLedgerHistoryEntryId = nil
            editor.selectedLootLedgerHistoryOwner = nil
            if flowMode == "REQUEST_SENT" then
              feedback:SetText("Character delete request sent to the session host.")
            else
              feedback:SetText("Character deleted from the Loot List.")
            end
            if editor.Refresh then editor:Refresh() end
          else
            feedback:SetText(tostring(result or "Could not delete the character."))
          end
        end,
      }
    end
  end

  local function GetSelectedLootListAccess()
    local profileName = TrimText(GetLootListContextProfileName())
    if profileName == "" then
      return EMPTY_LOOT_LIST_ACCESS
    end
    return GetLootProfileAccessInfo(profileName)
  end

  addBtn:SetScript("OnClick", function()
    local access = GetSelectedLootListAccess()
    if not access.canEditManualPoints then
      feedback:SetText("Raiders can view the Loot List, but cannot add manual points.")
      return
    end
    local profileName = GetLootListContextProfileName()
    local selectedType = tostring(editor.selectedLootLedgerType or "")
    if selectedType ~= "character" then
      feedback:SetText("Select a character row to add manual points.")
      return
    end
    local selectedCharacter = TrimText(editor.selectedLootLedgerCharacter)
    if selectedCharacter == "" then
      feedback:SetText("Select a character row to add manual points.")
      return
    end
    local requestManualEntry = type(ResolveOptionalApiFunction) == "function"
      and ResolveOptionalApiFunction("LIDCOUNCIL_RequestManualLootLedgerEntryFlow")
      or nil
    local ok, result, flowMode
    if type(requestManualEntry) == "function" then
      ok, result, flowMode = requestManualEntry(
        profileName,
        selectedCharacter,
        itemEdit:GetText(),
        pointsEdit:GetText(),
        ""
      )
    else
      ok, result = AddLootLedgerEntry(
        profileName,
        selectedCharacter,
        itemEdit:GetText(),
        nil,
        pointsEdit:GetText(),
        "",
        nil,
        nil,
        "Interface\\Icons\\INV_Misc_Note_06",
        nil,
        {
          grantedBy = GetCharacterKey(),
          isManual = true,
        }
      )
      flowMode = "LOCAL"
    end
    if ok then
      editor.selectedLootLedgerType = "character"
      editor.selectedLootLedgerKey = selectedCharacter
      editor.selectedLootLedgerCharacter = selectedCharacter
      itemEdit:SetText("")
      pointsEdit:SetText("")
      if flowMode == "REQUEST_SENT" then
        feedback:SetText("Manual points sent to the session host.")
      else
        feedback:SetText("Manual points added.")
      end
      if editor.Refresh then editor:Refresh() end
    else
      feedback:SetText(tostring(result or "Could not add ledger entry."))
    end
  end)

  deleteManualBtn:SetScript("OnClick", function()
    local access = GetSelectedLootListAccess()
    if not access.canEditManualPoints then
      feedback:SetText("Raiders can view the Loot List, but cannot delete manual points.")
      return
    end
    local entryId = TrimText(editor.selectedLootLedgerHistoryEntryId)
    local ownerKey = TrimText(editor.selectedLootLedgerHistoryOwner)
    if entryId == "" or ownerKey == "" then
      feedback:SetText("Select a manual history entry first.")
      return
    end
    local profileName = GetLootListContextProfileName()
    local requestManualDelete = type(ResolveOptionalApiFunction) == "function"
      and ResolveOptionalApiFunction("LIDCOUNCIL_RequestManualLootLedgerDeleteFlow")
      or nil
    local ok, result, flowMode
    if type(requestManualDelete) == "function" then
      ok, result, flowMode = requestManualDelete(profileName, ownerKey, entryId)
    else
      ok, result = RemoveLootLedgerEntry(profileName, ownerKey, entryId)
      flowMode = "LOCAL"
    end
    if ok then
      editor.selectedLootLedgerHistoryEntryId = nil
      editor.selectedLootLedgerHistoryOwner = nil
      if flowMode == "REQUEST_SENT" then
        feedback:SetText("Manual point delete request sent to the session host.")
      else
        feedback:SetText("Manual points removed.")
      end
      if editor.Refresh then editor:Refresh() end
    else
      feedback:SetText(tostring(result or "Could not remove manual entry."))
    end
  end)

  deleteCharacterBtn:SetScript("OnClick", function()
    local access = GetSelectedLootListAccess()
    if not access.canDeleteLootListCharacter then
      feedback:SetText("Your current role cannot delete Loot List characters.")
      return
    end
    if TrimText(editor.selectedLootLedgerCharacter) == "" or tostring(editor.selectedLootLedgerType or "") ~= "character" then
      feedback:SetText("Select a character first.")
      return
    end
    StaticPopup_Show("LIDCOUNCIL_DELETE_LOOT_LEDGER_CHARACTER")
  end)

  searchEdit:SetScript("OnTextChanged", function(self)
    editor.__lootLedgerSearchText = TrimText(self:GetText())
    if editor.Refresh then
      editor:Refresh()
    end
  end)

  modeListBtn:SetScript("OnClick", function()
    local root = RootDB()
    root.ui = root.ui or {}
    root.ui.lootLedgerViewMode = "LIST_ONLY"
    UpdateLootListModeButtons()
    if editor.Refresh then
      editor:Refresh()
    end
  end)

  modeDetailsBtn:SetScript("OnClick", function()
    local root = RootDB()
    root.ui = root.ui or {}
    root.ui.lootLedgerViewMode = "DETAILS"
    UpdateLootListModeButtons()
    if editor.Refresh then
      editor:Refresh()
    end
  end)

  modeAwardsBtn:SetScript("OnClick", function()
    UpdateLootListModeButtons()
    local profileName = TrimText(GetLootListContextProfileName())
    if profileName ~= "" and editor.OpenLootLedgerAwardsPopup then
      editor:OpenLootLedgerAwardsPopup(profileName)
    end
    UpdateLootListModeButtons()
  end)

  addGroupBtn:SetScript("OnClick", nil)
  deleteGroupBtn:SetScript("OnClick", nil)
  navBg:SetScript("OnMouseUp", nil)
  charContent:SetScript("OnReceiveDrag", nil)

  seedTestBtn:SetScript("OnClick", function()
    local access = GetSelectedLootListAccess()
    if not access.canEditLootList then
      if editor.lootLedgerDragHint then
        editor.lootLedgerDragHint:SetText("Raiders can view the Loot List, but cannot modify it.")
      end
      return
    end
    local profile, profileName = GetLootProfile(GetLootListContextProfileName())
    if TrimText(profileName) ~= "Simulation" then
      if editor.lootLedgerDragHint then
        editor.lootLedgerDragHint:SetText("Seed Test Raiders is only available for the Simulation profile.")
      end
      return
    end
    local ok, result = SeedLootLedgerTestRoster(profile, profileName)
    if editor.lootLedgerDragHint then
      editor.lootLedgerDragHint:SetText(tostring(result or (ok and "Test raiders added." or "Could not seed test raiders.")))
    end
    if ok and editor.Refresh then
      editor:Refresh()
    end
  end)

  linkSummaryBtn:SetScript("OnClick", function()
    local access = GetSelectedLootListAccess()
    if not access.canEditMainAlt then
      if editor.lootLedgerDragHint then
        editor.lootLedgerDragHint:SetText("Raiders can view Main and Alt links, but cannot change them.")
      end
      return
    end
    local profileName = GetLootListContextProfileName()
    local profile = GetLootProfile(profileName)
    local selectedCharacter = TrimText(editor.selectedLootLedgerCharacter)
    if selectedCharacter == "" then
      if editor.lootLedgerDragHint then
        editor.lootLedgerDragHint:SetText("Select a character first.")
      end
      return
    end

    local selectedRole = "MAIN"
    if roleDropdown and roleDropdown.GetSelectedValue then
      selectedRole = NormalizeLootLedgerRoleLocal(roleDropdown:GetSelectedValue())
    elseif roleDropdown and roleDropdown.GetText then
      selectedRole = NormalizeLootLedgerRoleLocal(roleDropdown:GetText())
    end

    local targetCharacter = ""
    if summaryDropdown and summaryDropdown.GetSelectedValue then
      targetCharacter = TrimText(summaryDropdown:GetSelectedValue())
    elseif summaryDropdown and summaryDropdown.GetText then
      targetCharacter = TrimText(summaryDropdown:GetText())
    end

    local requestMainAlt = type(ResolveOptionalApiFunction) == "function"
      and ResolveOptionalApiFunction("LIDCOUNCIL_RequestLootLedgerMainAltFlow")
      or nil
    local ok, result, flowMode
    if type(requestMainAlt) == "function" then
      ok, result, flowMode = requestMainAlt(profileName, selectedCharacter, selectedRole, selectedRole == "ALT" and targetCharacter or "")
    elseif selectedRole == "ALT" then
      ok, result = SetLootLedgerMainAltRole(profile, selectedCharacter, selectedRole)
      if ok then
        local _, allCharactersByKey = BuildLootLedgerNavRows(profile, profileName, "")
        ok, result = SetLootLedgerMainCharacter(profile, selectedCharacter, targetCharacter, allCharactersByKey)
      end
      flowMode = "LOCAL"
    else
      ok, result = ClearLootLedgerMainCharacter(profile, selectedCharacter)
      flowMode = "LOCAL"
    end

    if not ok then
      if editor.lootLedgerDragHint then
        editor.lootLedgerDragHint:SetText(tostring(result or "Could not update the Main / Alt link."))
      end
      return
    end

    if flowMode == "REQUEST_SENT" then
      editor.__lootLedgerPendingRole = nil
      editor.__lootLedgerPendingRoleCharacter = nil
      if editor.lootLedgerDragHint then
        editor.lootLedgerDragHint:SetText("Main / Alt update sent to the session host.")
      end
      if editor.Refresh then editor:Refresh() end
      return
    end

    if selectedRole == "ALT" then
      editor.__lootLedgerPendingRole = nil
      editor.__lootLedgerPendingRoleCharacter = nil
      if editor.lootLedgerDragHint then
        if TrimText(result) ~= "" then
          editor.lootLedgerDragHint:SetText(tostring(selectedCharacter) .. " is now an Alt assigned to " .. tostring(result) .. ".")
        else
          editor.lootLedgerDragHint:SetText(tostring(selectedCharacter) .. " is now an Alt without a Main assigned yet.")
        end
      end
      if editor.Refresh then editor:Refresh() end
      return
    end

    editor.__lootLedgerPendingRole = nil
    editor.__lootLedgerPendingRoleCharacter = nil
    if editor.lootLedgerDragHint then
      editor.lootLedgerDragHint:SetText(tostring(selectedCharacter) .. " is now a Main.")
    end
    if editor.Refresh then editor:Refresh() end
  end)

  clearSummaryBtn:SetScript("OnClick", function()
    local access = GetSelectedLootListAccess()
    if not access.canEditMainAlt then
      if editor.lootLedgerDragHint then
        editor.lootLedgerDragHint:SetText("Raiders can view Main and Alt links, but cannot change them.")
      end
      return
    end
    local profileName = GetLootListContextProfileName()
    local profile = GetLootProfile(profileName)
    local selectedCharacter = TrimText(editor.selectedLootLedgerCharacter)
    local requestMainAlt = type(ResolveOptionalApiFunction) == "function"
      and ResolveOptionalApiFunction("LIDCOUNCIL_RequestLootLedgerMainAltFlow")
      or nil
    local ok, result, flowMode
    if type(requestMainAlt) == "function" then
      ok, result, flowMode = requestMainAlt(profileName, selectedCharacter, "MAIN", "")
    else
      ok, result = ClearLootLedgerMainCharacter(profile, selectedCharacter)
      flowMode = "LOCAL"
    end
    if ok then
      editor.__lootLedgerPendingRole = nil
      editor.__lootLedgerPendingRoleCharacter = nil
      if editor.lootLedgerDragHint then
        if flowMode == "REQUEST_SENT" then
          editor.lootLedgerDragHint:SetText("Main / Alt update sent to the session host.")
        else
          editor.lootLedgerDragHint:SetText(tostring(selectedCharacter) .. " is now a Main.")
        end
      end
      if editor.Refresh then editor:Refresh() end
    elseif editor.lootLedgerDragHint then
      editor.lootLedgerDragHint:SetText(tostring(result or "Could not set the character as Main."))
    end
  end)

  local function CommitLootLedgerCharacterNote()
    local access = GetSelectedLootListAccess()
    if not access.canEditNotes then
      if editor.lootLedgerDragHint then
        editor.lootLedgerDragHint:SetText("Raiders can view notes, but cannot edit them.")
      end
      return
    end
    local profile = GetLootProfile(GetLootListContextProfileName())
    local selectedCharacter = TrimText(editor.selectedLootLedgerCharacter)
    if selectedCharacter == "" or not editor.lootLedgerCharacterNoteEdit then
      return
    end

    local currentNote = TrimText(editor.lootLedgerCharacterNoteEdit:GetText())
    local meta = EnsureLootLedgerMetaLocal(profile)[selectedCharacter]
    local storedNote = TrimText(type(meta) == "table" and meta.note or "")
    if currentNote == storedNote then
      return
    end

    local requestNote = type(ResolveOptionalApiFunction) == "function"
      and ResolveOptionalApiFunction("LIDCOUNCIL_RequestLootLedgerCharacterNoteFlow")
      or nil
    local ok, result, flowMode
    if type(requestNote) == "function" then
      ok, result, flowMode = requestNote(GetLootListContextProfileName(), selectedCharacter, currentNote)
    else
      ok, result = SetLootLedgerCharacterNote(profile, selectedCharacter, currentNote)
      flowMode = "LOCAL"
    end
    if editor.lootLedgerDragHint then
      if ok then
        if flowMode == "REQUEST_SENT" then
          editor.lootLedgerDragHint:SetText("Character note update sent to the session host.")
        elseif currentNote ~= "" then
          editor.lootLedgerDragHint:SetText("Updated note for " .. tostring(selectedCharacter) .. ".")
        else
          editor.lootLedgerDragHint:SetText("Cleared note for " .. tostring(selectedCharacter) .. ".")
        end
      else
        editor.lootLedgerDragHint:SetText(tostring(result or "Could not update the character note."))
      end
    end
    if ok and editor.Refresh then
      editor:Refresh()
    end
  end

  if editor.lootLedgerCharacterNoteEdit then
    editor.lootLedgerCharacterNoteEdit:SetScript("OnEnterPressed", function(self)
      CommitLootLedgerCharacterNote()
      self:ClearFocus()
    end)
    editor.lootLedgerCharacterNoteEdit:SetScript("OnEditFocusLost", function()
      CommitLootLedgerCharacterNote()
    end)
    editor.lootLedgerCharacterNoteEdit:SetScript("OnEscapePressed", function(self)
      local profile = GetLootProfile(GetLootListContextProfileName())
      local selectedCharacter = TrimText(editor.selectedLootLedgerCharacter)
      local meta = selectedCharacter ~= "" and EnsureLootLedgerMetaLocal(profile)[selectedCharacter] or nil
      self:SetText(type(meta) == "table" and TrimText(meta.note) or "")
      self:ClearFocus()
    end)
  end

  editor.RefreshLootListPage = function(self)
    EnsureLootListStaticPopups()
    local hasActiveProfile = TrimText(GetLootListContextProfileName()) ~= ""
    if self.lootListInactiveOverlay then
      self.lootListInactiveOverlay:SetShown(not hasActiveProfile)
    end
    if self.backgroundsTitle then
      self.backgroundsTitle:SetText(hasActiveProfile and "Loot List" or "Profile")
    end
    if self.lootListNavBg then
      self.lootListNavBg:SetShown(hasActiveProfile)
    end
    if self.lootListRightBg then
      self.lootListRightBg:SetShown(hasActiveProfile)
    end
    if not hasActiveProfile then
      SetCurrentProfileFont(self.backgroundsCurrentLabel, NO_ACTIVE_PROFILE_CURRENT_TEXT, NO_ACTIVE_PROFILE_TEXT_COLOR)
      if self.UpdateScrollLayout then
        self:UpdateScrollLayout()
      end
      return
    end
    local profileName = TrimText(GetLootListContextProfileName())
    SetCurrentProfileFont(self.backgroundsCurrentLabel, "Current Profile: " .. profileName, nil)
    return RefreshLootListPageImpl(self, page)
  end
end

INTERNAL_API.LIDCOUNCIL_BuildLootListPage_Impl = BuildLootListPage

