-- LidCouncil_Editor.lua
-- ============================================================

-- NOTE: Load order: Core -> Panels -> Editor -> Init

local LogInfo = _G.LIDCOUNCIL_LogInfo
local LogError = _G.LIDCOUNCIL_LogError
local LogSilent = _G.LIDCOUNCIL_LogSilent
local Compat = _G.LIDCOUNCIL_Compat
local function GetDebugStore()
  return _G.LIDCOUNCIL_Debug
end
local function GetBootstrapState()
  local state = _G.LIDCOUNCIL_BootstrapState
  if type(state) ~= "table" then
    state = {}
    _G.LIDCOUNCIL_BootstrapState = state
  end
  state.issues = type(state.issues) == "table" and state.issues or {}
  state._seen = type(state._seen) == "table" and state._seen or {}
  return state
end
local function RecordBootstrapIssue(area, message)
  local resolvedArea = tostring(area or "Bootstrap")
  local resolvedMessage = tostring(message or "Unknown bootstrap issue.")
  local state = GetBootstrapState()
  local issueKey = resolvedArea .. "|" .. resolvedMessage
  if state._seen[issueKey] then
    return
  end
  state._seen[issueKey] = true
  state.issues[#state.issues + 1] = {
    area = resolvedArea,
    message = resolvedMessage,
  }
  if LogSilent then
    LogSilent("[" .. resolvedArea .. "] " .. resolvedMessage)
  elseif LogError then
    LogError("[" .. resolvedArea .. "] " .. resolvedMessage)
  end
end
local function GetBootstrapIssueText()
  local issues = GetBootstrapState().issues
  if type(issues) ~= "table" or #issues == 0 then
    return ""
  end
  local first = issues[1]
  local summary = tostring(first and first.message or "Bootstrap issue detected.")
  if #issues > 1 then
    summary = summary .. " +" .. tostring(#issues - 1) .. " more."
  end
  return summary
end
_G.LIDCOUNCIL_GetBootstrapIssueText = GetBootstrapIssueText
if LogInfo then LogInfo("Editor.lua loaded") end

local function ReportEditorRuntimeError(label, err)
  if not LogError then return end
  LogError("[" .. tostring(label or "Editor") .. "] " .. tostring(err))
  if debugstack then
    LogError(debugstack(3, 8, 8))
  end
end

local function RequireApi(name, value)
  if value == nil then
    value = rawget(_G, name)
  end
  if value == nil then
    local api = rawget(_G, "LIDCOUNCIL_API")
    if type(api) == "table" then
      value = api[name]
    end
  end
  if value == nil then
    error("LidCouncil missing API: " .. tostring(name))
  end
  return value
end

local INTERNAL_API = (function()
  local api = rawget(_G, "LIDCOUNCIL_API")
  if type(api) ~= "table" or type(api.__internal) ~= "table" then
    RecordBootstrapIssue("Editor Bootstrap", "Missing internal API registry.")
    return {}
  end
  return api.__internal
end)()

local function RequireInternalApi(name)
  local value = INTERNAL_API[name]
  if value == nil then
    RecordBootstrapIssue("Editor Bootstrap", "Missing internal API: " .. tostring(name))
  end
  return value
end

local RootDB = RequireApi("LIDCOUNCIL_RootDB", _G.LIDCOUNCIL_RootDB)
local DB = RequireApi("LIDCOUNCIL_DB", _G.LIDCOUNCIL_DB)
local DeepCopy = RequireApi("LIDCOUNCIL_DeepCopy", _G.LIDCOUNCIL_DeepCopy)
local EnsureDefaults = RequireApi("LIDCOUNCIL_EnsureDefaults", _G.LIDCOUNCIL_EnsureDefaults)
local Print = RequireApi("LIDCOUNCIL_Print", _G.LIDCOUNCIL_Print)
local RebuildAllPanels = RequireApi("LIDCOUNCIL_RebuildAllPanels", _G.LIDCOUNCIL_RebuildAllPanels)
local SetAllUnlocked = RequireApi("LIDCOUNCIL_SetAllUnlocked", _G.LIDCOUNCIL_SetAllUnlocked)
local NudgeSelectedPanel = RequireApi("LIDCOUNCIL_NudgeSelectedPanel", _G.LIDCOUNCIL_NudgeSelectedPanel)
local EnsureGradientTables = RequireApi("LIDCOUNCIL_EnsureGradientTables", _G.LIDCOUNCIL_EnsureGradientTables)
local GetEnabledLootProfileName = RequireApi("LIDCOUNCIL_GetEnabledLootProfileName", _G.LIDCOUNCIL_GetEnabledLootProfileName)
local GetCharacterKey = RequireApi("LIDCOUNCIL_GetCharacterKey", _G.LIDCOUNCIL_GetCharacterKey)
local function TrimText(value)
  value = tostring(value or "")
  value = value:gsub("^%s+", "")
  value = value:gsub("%s+$", "")
  return value
end
local function CreateFallbackEditorWindowStateBridge()
  return {
    ApplyEditorState = function(frame)
      if frame and frame.SetSize and (tonumber(frame:GetWidth()) or 0) < 1 then
        frame:SetSize(1180, 760)
      end
    end,
    GetEditorScale = function()
      return 1
    end,
    ApplyEditorScale = function() end,
    SetDropdownSelection = function(dropdown, value, text)
      if not dropdown then return end
      if value ~= nil and type(UIDropDownMenu_SetSelectedValue) == "function" then
        UIDropDownMenu_SetSelectedValue(dropdown, value)
      end
      if text ~= nil and type(UIDropDownMenu_SetText) == "function" then
        UIDropDownMenu_SetText(dropdown, text)
      end
    end,
    ApplyDropdownLimits = function() end,
    SaveEditorState = function() end,
  }
end

local CreateEditorWindowStateBridge = RequireInternalApi("LIDCOUNCIL_CreateEditorWindowStateBridge")
if type(CreateEditorWindowStateBridge) ~= "function" then
  CreateEditorWindowStateBridge = function()
    return CreateFallbackEditorWindowStateBridge()
  end
end

local SetupEditorFrameShell = RequireInternalApi("LIDCOUNCIL_SetupEditorFrameShell")
local BindEditorTheme = RequireInternalApi("LIDCOUNCIL_BindEditorTheme")
local frames = _G.LIDCOUNCIL_PanelFrames or {}
_G.LIDCOUNCIL_PanelFrames = frames

local EditorWindowState = CreateEditorWindowStateBridge({
  RootDB = RootDB,
})
local ApplyEditorState = EditorWindowState.ApplyEditorState
local GetEditorScale = EditorWindowState.GetEditorScale
local ApplyEditorScale = EditorWindowState.ApplyEditorScale
local SetDropdownSelection = EditorWindowState.SetDropdownSelection
local ApplyDropdownLimits = EditorWindowState.ApplyDropdownLimits
local SaveEditorState = EditorWindowState.SaveEditorState

-- Editor runtime state stays file-local; cross-file access goes through LIDCOUNCIL_* APIs.
local editor
local selectedPanelName
local selectedBackgroundName
local selectedBackgroundCategory
local selectedBackgroundCategoryGroup

local function GetPanelsUnlockedState()
  local unlocked = _G.LIDCOUNCIL_PanelsUnlocked
  if unlocked == nil then
    return true
  end
  return unlocked
end

local function OpenColorPickerRGBOnly(initialRGB, onChangedRGB, initialAlpha)
  local r, g, b = initialRGB[1] or 1, initialRGB[2] or 1, initialRGB[3] or 1
  local hasOpacity = initialAlpha ~= nil
  local a = initialAlpha
  if ColorPickerFrame then
    ColorPickerFrame.__lidCouncilAcceptCallback = nil
  end

  local function ApplyNow()
    local nr, ng, nb = ColorPickerFrame:GetColorRGB()
    local na = nil
    if hasOpacity and ColorPickerFrame.GetColorAlpha then
      na = ColorPickerFrame:GetColorAlpha()
    end
    onChangedRGB(nr, ng, nb, na)
  end

  local function ApplyPrevious(prev)
    local pr, pg, pb, pa = r, g, b, a
    if type(prev) == "table" then
      pr = prev.r or prev[1] or pr
      pg = prev.g or prev[2] or pg
      pb = prev.b or prev[3] or pb
      if hasOpacity then
        pa = prev.opacity
        if pa == nil then pa = prev.a end
        if pa == nil then pa = prev[4] end
        if pa == nil then pa = a end
      end
    elseif hasOpacity and ColorPickerFrame.GetPreviousValues then
      local vr, vg, vb, va = ColorPickerFrame:GetPreviousValues()
      pr = vr or pr
      pg = vg or pg
      pb = vb or pb
      pa = va
      if pa == nil then pa = a end
    end
    onChangedRGB(pr, pg, pb, pa)
  end

  if ColorPickerFrame and ColorPickerFrame.SetupColorPickerAndShow then
    local info = {
      r = r, g = g, b = b,
      swatchFunc = ApplyNow,
      colorFunc  = ApplyNow, -- LIVE while dragging (when supported)
      cancelFunc = function(prev)
        ApplyPrevious(prev)
      end,
    }
    if hasOpacity then
      info.hasOpacity = true
      info.opacity = a
      info.opacityFunc = ApplyNow
    else
      info.hasOpacity = false
    end
    ColorPickerFrame:SetupColorPickerAndShow(info)
    return
  end

  local cp = ColorPickerFrame
  cp.func = function() ApplyNow() end
  cp.swatchFunc = function() ApplyNow() end
  cp.cancelFunc = function() ApplyPrevious() end
  if cp.opacityFunc ~= nil or hasOpacity then
    cp.opacityFunc = function() ApplyNow() end
  end
  if cp.SetHasOpacity then cp:SetHasOpacity(hasOpacity) end
  cp.hasOpacity = hasOpacity
  cp.opacity = a
  if cp.SetColorRGB then cp:SetColorRGB(r, g, b) end
  cp:Show()
end

local function OpenColorPickerRGBOnlyOnAccept(initialRGB, onAcceptedRGB, initialAlpha)
  local r, g, b = initialRGB[1] or 1, initialRGB[2] or 1, initialRGB[3] or 1
  local hasOpacity = initialAlpha ~= nil
  local a = initialAlpha
  local applied = false

  local function ApplyAccepted()
    if applied then
      return
    end
    applied = true
    local nr, ng, nb = ColorPickerFrame:GetColorRGB()
    local na = nil
    if hasOpacity and ColorPickerFrame.GetColorAlpha then
      na = ColorPickerFrame:GetColorAlpha()
    end
    onAcceptedRGB(nr, ng, nb, na)
  end

  local function ClearAcceptedCallback()
    if ColorPickerFrame and ColorPickerFrame.__lidCouncilAcceptCallback == ApplyAccepted then
      ColorPickerFrame.__lidCouncilAcceptCallback = nil
    end
  end

  local function HookAcceptButton()
    if not ColorPickerFrame then
      return
    end
    ColorPickerFrame.__lidCouncilAcceptCallback = ApplyAccepted
    local buttons = {
      ColorPickerFrame.OkayButton,
      ColorPickerFrame.okayButton,
      ColorPickerFrame.Footer and ColorPickerFrame.Footer.OkayButton,
      _G.ColorPickerOkayButton,
    }
    for _, button in ipairs(buttons) do
      if button and button.HookScript and not button.__lidCouncilAcceptHooked then
        button:HookScript("OnClick", function()
          local callback = ColorPickerFrame and ColorPickerFrame.__lidCouncilAcceptCallback
          if type(callback) == "function" then
            callback()
            ColorPickerFrame.__lidCouncilAcceptCallback = nil
          end
        end)
        button.__lidCouncilAcceptHooked = true
      end
    end
  end

  if ColorPickerFrame and ColorPickerFrame.SetupColorPickerAndShow then
    local info = {
      r = r, g = g, b = b,
      swatchFunc = function() end,
      cancelFunc = function()
        ClearAcceptedCallback()
      end,
    }
    if hasOpacity then
      info.hasOpacity = true
      info.opacity = a
    else
      info.hasOpacity = false
    end
    ColorPickerFrame:SetupColorPickerAndShow(info)
    HookAcceptButton()
    return
  end

  local cp = ColorPickerFrame
  cp.func = nil
  cp.swatchFunc = function() end
  cp.cancelFunc = function()
    ClearAcceptedCallback()
  end
  cp.opacityFunc = nil
  if cp.SetHasOpacity then cp:SetHasOpacity(hasOpacity) end
  cp.hasOpacity = hasOpacity
  cp.opacity = a
  if cp.SetColorRGB then cp:SetColorRGB(r, g, b) end
  cp:Show()
  HookAcceptButton()
end

-- ============================================================
-- ##--------------------------EDITOR UI HELPERS----------------
-- ============================================================

local MAX_PANEL_NAME = 25
local MAX_PROFILE_NAME = 25
local MAX_PROFILE_GROUP_NAME = 25
local MAX_BACKGROUND_NAME = 25
local MAX_BG_CATEGORY_NAME = 25
local MAX_BG_CATEGORY_GROUP_NAME = 25
local LISTS_PER_PAGE = 18

local ADDON_VERSION = "1.0.1 [BETA]"
local WOW_CLIENT_VERSION = "12.1.0 (Build 69299)"

-- Logo sizing (kept consistent across header + tutorial).
local LOGO_SRC_W = 2257
local LOGO_SRC_H = 1794
local LOGO_TARGET_W = 150
local LOGO_TARGET_H = math.floor((LOGO_TARGET_W * LOGO_SRC_H / LOGO_SRC_W) + 0.5)

-- Tutorial/Welcome card sizing (kept constant, layout adapts by columns).
local CARD_W = 320
local CARD_H = 240

local function Noop() end
local function CreateFallbackButton(parent, text)
  local button = CreateFrame("Button", nil, parent, "UIPanelButtonTemplate")
  button:SetSize(120, 22)
  if text ~= nil and button.SetText then
    button:SetText(tostring(text))
  end
  return button
end

local EDITOR_UI_HELPERS_FALLBACK = {
  ApplySkinPreset = Noop,
  ApplyFrameSkin = Noop,
  ApplyEditorLogo = Noop,
  ApplyHeaderBackground = Noop,
  BuildBackgroundList = function()
    return {}
  end,
  MakeYellowSubHeader = function(parent, text)
    if not parent or type(parent.CreateFontString) ~= "function" then
      return nil
    end
    local label = parent:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    label:SetText(tostring(text or ""))
    return label
  end,
  MakeSlider = function(parent)
    local frame = CreateFrame("Frame", nil, parent)
    frame.SetValue = Noop
    return frame
  end,
  CreatePurpleOutline = function()
    return nil
  end,
  MakeListButton = function(parent, text)
    return CreateFallbackButton(parent, text)
  end,
  MakeSimpleListButton = function(parent, text)
    return CreateFallbackButton(parent, text)
  end,
  ConfigureProfileGroupButton = Noop,
  ConfigureBackgroundCategoryGroupButton = Noop,
  MakeProfileButton = function(parent, text)
    return CreateFallbackButton(parent, text)
  end,
  ClampListPage = function(page, maxPage)
    page = math.max(1, tonumber(page) or 1)
    maxPage = math.max(1, tonumber(maxPage) or 1)
    if page > maxPage then
      page = maxPage
    end
    return page
  end,
  GetListPageForValue = function()
    return 1
  end,
  UpdatePagerControls = Noop,
}

local EDITOR_PROFILE_HELPERS_FALLBACK = {
  FindProfileGroupIndex = function()
    return nil
  end,
  EnsureProfileGroups = function()
    return {}
  end,
  BuildVisibleProfileRows = function()
    return {}
  end,
  GetProfileFocusKey = function()
    return nil
  end,
  ToggleProfileGroupCollapsed = Noop,
  InvalidateSortedProfileNames = Noop,
  AssignProfileToGroup = function()
    return false
  end,
  SwitchProfile = function()
    return false
  end,
}

local EDITOR_PANEL_HELPERS_FALLBACK = {
  InvalidateSortedPanelNames = Noop,
  GetSortedPanelNames = function()
    return {}
  end,
  SelectPanel = Noop,
  GetSelectedPanelName = function()
    return nil
  end,
  CreateNewPanelNamed = function()
    return false
  end,
  DeleteSelectedPanel = function()
    return false
  end,
  RenameSelectedPanel = function()
    return false
  end,
  CopySelectedPanel = function()
    return false
  end,
  CopySelectedPanelToProfile = function()
    return false
  end,
}

local EDITOR_BACKGROUND_HELPERS_FALLBACK = {
  InvalidateSortedBackgroundNames = Noop,
  GetSortedBackgroundNames = function()
    return {}
  end,
  ListBackgroundCategories = function()
    return {}
  end,
  ListBackgrounds = function()
    return {}
  end,
  FindBackgroundIndex = function()
    return nil
  end,
  FindCategoryIndex = function()
    return nil
  end,
  EnsureBackgroundCategoryGroups = function()
    return {}
  end,
  FindBackgroundCategoryGroupIndex = function()
    return nil
  end,
  BuildVisibleBackgroundCategoryRows = function()
    return {}
  end,
  GetBackgroundCategoryFocusKey = function()
    return nil
  end,
  ToggleBackgroundCategoryGroupCollapsed = Noop,
  SelectBackground = Noop,
  CreateBackgroundNamed = function()
    return false
  end,
  RenameBackground = function()
    return false
  end,
  DeleteBackground = function()
    return false
  end,
  CreateBackgroundCategoryNamed = function()
    return false
  end,
  RenameBackgroundCategory = function()
    return false
  end,
  DeleteBackgroundCategory = function()
    return false
  end,
  CreateBackgroundCategoryGroupNamed = function()
    return false
  end,
  RenameBackgroundCategoryGroup = function()
    return false
  end,
  DeleteBackgroundCategoryGroup = function()
    return false
  end,
  ClearBackgroundCategoryDragState = Noop,
  BeginBackgroundCategoryDrag = Noop,
  BeginBackgroundCategoryGroupDrag = Noop,
}

local function GetEditorUiHelpers()
  local impl = INTERNAL_API.LIDCOUNCIL_EditorUiHelpers_Impl
  if type(impl) ~= "table" then
    RecordBootstrapIssue("Editor UI", "Missing editor UI helpers.")
    return EDITOR_UI_HELPERS_FALLBACK
  end
  return impl
end

local function ApplySkinPreset(...)
  return GetEditorUiHelpers().ApplySkinPreset(...)
end

local function ApplyFrameSkin(...)
  return GetEditorUiHelpers().ApplyFrameSkin(...)
end

local function ApplyEditorLogo(...)
  return GetEditorUiHelpers().ApplyEditorLogo(...)
end

local function ApplyHeaderBackground(...)
  return GetEditorUiHelpers().ApplyHeaderBackground(...)
end

local function BuildBackgroundList(...)
  return GetEditorUiHelpers().BuildBackgroundList(...)
end

local function MakeYellowSubHeader(...)
  return GetEditorUiHelpers().MakeYellowSubHeader(...)
end

local function MakeSlider(...)
  return GetEditorUiHelpers().MakeSlider(...)
end

local SelectPanel

local function CreatePurpleOutline(...)
  return GetEditorUiHelpers().CreatePurpleOutline(...)
end

local function MakeListButton(...)
  return GetEditorUiHelpers().MakeListButton(...)
end

local function MakeSimpleListButton(...)
  return GetEditorUiHelpers().MakeSimpleListButton(...)
end

local function ConfigureProfileGroupButton(...)
  return GetEditorUiHelpers().ConfigureProfileGroupButton(...)
end

local function ConfigureBackgroundCategoryGroupButton(...)
  return GetEditorUiHelpers().ConfigureBackgroundCategoryGroupButton(...)
end

local function MakeProfileButton(...)
  return GetEditorUiHelpers().MakeProfileButton(...)
end

local function ClampListPage(...)
  return GetEditorUiHelpers().ClampListPage(...)
end

local function GetListPageForValue(...)
  return GetEditorUiHelpers().GetListPageForValue(...)
end

local function UpdatePagerControls(...)
  return GetEditorUiHelpers().UpdatePagerControls(...)
end

local RenameSelectedPanel
local CopySelectedPanel
local DeleteSelectedPanel
local CreateNewPanelNamed
local TrimName
local ClampNameLen
local CreateBackgroundNamed
local RenameBackground
local DeleteBackground
local CreateBackgroundCategoryNamed
local DeleteBackgroundCategory
local RenameBackgroundCategory
local CreateBackgroundCategoryGroupNamed
local RenameBackgroundCategoryGroup
local DeleteBackgroundCategoryGroup
local CopySelectedPanelToProfile

local function GetEditorProfileHelpers()
  local impl = INTERNAL_API.LIDCOUNCIL_EditorProfileManagement_Impl
  if type(impl) ~= "table" then
    RecordBootstrapIssue("Editor Profiles", "Missing editor profile management helpers.")
    return EDITOR_PROFILE_HELPERS_FALLBACK
  end
  return impl
end

-- Popup dialog registration moved to Editor_PopupDialogs.lua.

-- ============================================================
-- ##--------------------------EDITOR WINDOW STATE---------------
-- ============================================================

-- ============================================================
-- ##--------------------------PROFILES HELPERS------------------
-- ============================================================

local function GetEditorPanelHelpers()
  local impl = INTERNAL_API.LIDCOUNCIL_EditorPanelManagement_Impl
  if type(impl) ~= "table" then
    RecordBootstrapIssue("Editor Panels", "Missing editor panel management helpers.")
    return EDITOR_PANEL_HELPERS_FALLBACK
  end
  return impl
end

local function InvalidateSortedPanelNames(...)
  return GetEditorPanelHelpers().InvalidateSortedPanelNames(...)
end

local function GetEditorBackgroundHelpers()
  local impl = INTERNAL_API.LIDCOUNCIL_EditorBackgroundManagement_Impl
  if type(impl) ~= "table" then
    RecordBootstrapIssue("Editor Backgrounds", "Missing editor background management helpers.")
    return EDITOR_BACKGROUND_HELPERS_FALLBACK
  end
  return impl
end

local function InvalidateSortedBackgroundNames(...)
  return GetEditorBackgroundHelpers().InvalidateSortedBackgroundNames(...)
end

local function GetSortedBackgroundNames(...)
  return GetEditorBackgroundHelpers().GetSortedBackgroundNames(...)
end

-- ============================================================
-- ##--------------------------EDITOR UI-------------------------
-- ============================================================

editor = nil
selectedPanelName = nil
selectedBackgroundName = nil
selectedBackgroundCategory = nil
selectedBackgroundCategoryGroup = nil

TrimName = function(name)
  if not name then return "" end
  name = tostring(name)
  name = name:gsub("^%s+", ""):gsub("%s+$", "")
  return name
end

local function GetBackgroundPath(name)
  return "Interface\\AddOns\\LidCouncil_UserMedia\\Your_Backgrounds\\" .. name .. ".tga"
end

local function ListBackgroundCategories(...)
  return GetEditorBackgroundHelpers().ListBackgroundCategories(...)
end

local function ListBackgrounds(...)
  return GetEditorBackgroundHelpers().ListBackgrounds(...)
end

local function FindBackgroundIndex(...)
  return GetEditorBackgroundHelpers().FindBackgroundIndex(...)
end

local function FindCategoryIndex(...)
  return GetEditorBackgroundHelpers().FindCategoryIndex(...)
end

local function EnsureBackgroundCategoryGroups(...)
  return GetEditorBackgroundHelpers().EnsureBackgroundCategoryGroups(...)
end

local function FindBackgroundCategoryGroupIndex(...)
  return GetEditorBackgroundHelpers().FindBackgroundCategoryGroupIndex(...)
end

local function BuildVisibleBackgroundCategoryRows(...)
  return GetEditorBackgroundHelpers().BuildVisibleBackgroundCategoryRows(...)
end

local function GetBackgroundCategoryFocusKey(...)
  return GetEditorBackgroundHelpers().GetBackgroundCategoryFocusKey(...)
end

local function ToggleBackgroundCategoryGroupCollapsed(...)
  return GetEditorBackgroundHelpers().ToggleBackgroundCategoryGroupCollapsed(...)
end

local function SelectBackground(...)
  return GetEditorBackgroundHelpers().SelectBackground(...)
end

CreateBackgroundNamed = function(...)
  return GetEditorBackgroundHelpers().CreateBackgroundNamed(...)
end

RenameBackground = function(...)
  return GetEditorBackgroundHelpers().RenameBackground(...)
end

DeleteBackground = function(...)
  return GetEditorBackgroundHelpers().DeleteBackground(...)
end

CreateBackgroundCategoryNamed = function(...)
  return GetEditorBackgroundHelpers().CreateBackgroundCategoryNamed(...)
end

RenameBackgroundCategory = function(...)
  return GetEditorBackgroundHelpers().RenameBackgroundCategory(...)
end

DeleteBackgroundCategory = function(...)
  return GetEditorBackgroundHelpers().DeleteBackgroundCategory(...)
end

CreateBackgroundCategoryGroupNamed = function(...)
  return GetEditorBackgroundHelpers().CreateBackgroundCategoryGroupNamed(...)
end

RenameBackgroundCategoryGroup = function(...)
  return GetEditorBackgroundHelpers().RenameBackgroundCategoryGroup(...)
end

DeleteBackgroundCategoryGroup = function(...)
  return GetEditorBackgroundHelpers().DeleteBackgroundCategoryGroup(...)
end

local function ClearBackgroundCategoryDragState(...)
  return GetEditorBackgroundHelpers().ClearBackgroundCategoryDragState(...)
end

local function BeginBackgroundCategoryDrag(...)
  return GetEditorBackgroundHelpers().BeginBackgroundCategoryDrag(...)
end

local function BeginBackgroundCategoryGroupDrag(...)
  return GetEditorBackgroundHelpers().BeginBackgroundCategoryGroupDrag(...)
end

local function GetEditorProfileDragHelpers()
  local impl = INTERNAL_API.LIDCOUNCIL_EditorProfileDrag_Impl
  if type(impl) ~= "table" then
    error("LidCouncil missing editor profile drag helpers.")
  end
  return impl
end

local ClearProfileGroupDragState
local CancelProfileGroupDrag
local CompleteProfileGroupDrag
local MoveProfileToGroup
local EnsureProfileGroupDragBadge

MoveProfileToGroup = function(...)
  return GetEditorProfileDragHelpers().MoveProfileToGroup(...)
end

EnsureProfileGroupDragBadge = function(...)
  return GetEditorProfileDragHelpers().EnsureProfileGroupDragBadge(...)
end

ClearProfileGroupDragState = function(...)
  return GetEditorProfileDragHelpers().ClearProfileGroupDragState(...)
end

CancelProfileGroupDrag = function(...)
  return GetEditorProfileDragHelpers().CancelProfileGroupDrag(...)
end

CompleteProfileGroupDrag = function(...)
  return GetEditorProfileDragHelpers().CompleteProfileGroupDrag(...)
end

local function BeginProfileGroupDrag(...)
  return GetEditorProfileDragHelpers().BeginProfileGroupDrag(...)
end

ClampNameLen = function(name, maxLen, label)
  if not name then return "" end
  if #name > maxLen then
    local trimmed = string.sub(name, 1, maxLen)
    Print(label .. " name too long. Trimmed to: " .. trimmed)
    if LogSilent then LogSilent(label .. " name trimmed to: " .. trimmed) end
    return trimmed
  end
  return name
end

local function GetSortedPanelNames(...)
  return GetEditorPanelHelpers().GetSortedPanelNames(...)
end

local function SelectPanel(...)
  return GetEditorPanelHelpers().SelectPanel(...)
end

local function GetSelectedPanelName(...)
  return GetEditorPanelHelpers().GetSelectedPanelName(...)
end

local function GetSelectedBackgroundName()
  return selectedBackgroundName
end

local function GetSelectedBackgroundCategory()
  return selectedBackgroundCategory
end

CreateNewPanelNamed = function(...)
  return GetEditorPanelHelpers().CreateNewPanelNamed(...)
end

DeleteSelectedPanel = function(...)
  return GetEditorPanelHelpers().DeleteSelectedPanel(...)
end

RenameSelectedPanel = function(...)
  return GetEditorPanelHelpers().RenameSelectedPanel(...)
end

CopySelectedPanel = function(...)
  return GetEditorPanelHelpers().CopySelectedPanel(...)
end

CopySelectedPanelToProfile = function(...)
  return GetEditorPanelHelpers().CopySelectedPanelToProfile(...)
end

-- ============================================================
-- ##--------------------------EXPORT / IMPORT WINDOWS-----------
-- ============================================================

-- Floating log/export/import windows moved to Editor_FloatingWindows.lua.

-- ============================================================
-- ##--------------------------EDITOR CREATE---------------------
-- ============================================================

local function BuildUnavailablePage(pageFrame, label, reason)
  if not pageFrame or type(pageFrame.CreateFontString) ~= "function" then
    return
  end
  if not pageFrame.__bootstrapUnavailableTitle then
    local title = pageFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
    title:SetPoint("TOPLEFT", 14, -14)
    title:SetJustifyH("LEFT")
    pageFrame.__bootstrapUnavailableTitle = title

    local body = pageFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    body:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -12)
    body:SetPoint("RIGHT", pageFrame, "RIGHT", -18, 0)
    body:SetJustifyH("LEFT")
    body:SetJustifyV("TOP")
    body:SetSpacing(4)
    pageFrame.__bootstrapUnavailableBody = body
  end
  pageFrame.__bootstrapUnavailableTitle:SetText(tostring(label or "Unavailable"))
  pageFrame.__bootstrapUnavailableBody:SetText(
    "This section is unavailable because one or more LidCouncil files are missing, outdated, or failed to load.\n\n"
    .. tostring(reason or "Unknown bootstrap issue.")
  )
end

local function BuildFallbackEditorFrameShell(editor, deps)
  deps = type(deps) == "table" and deps or {}
  RecordBootstrapIssue("Editor Shell", "Missing editor frame shell builder. Loaded fallback shell.")
  local applyFrameSkin = deps.ApplyFrameSkin
  if type(applyFrameSkin) == "function" then
    pcall(applyFrameSkin, editor)
  end
  if editor.SetSize and (tonumber(editor:GetWidth()) or 0) < 1 then
    editor:SetSize(1180, 760)
  end

  editor.headerHeight = 70
  editor.profileBarHeight = 22
  editor.mainTabs = {}

  local shellTitle = editor.__bootstrapShellTitle
  if not shellTitle and type(editor.CreateFontString) == "function" then
    shellTitle = editor:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
    shellTitle:SetPoint("TOPLEFT", 14, -14)
    editor.__bootstrapShellTitle = shellTitle
  end
  if shellTitle then
    shellTitle:SetText("LidCouncil Limited Mode")
  end

  local shellNotice = editor.__bootstrapShellNotice
  if not shellNotice and type(editor.CreateFontString) == "function" then
    shellNotice = editor:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    shellNotice:SetPoint("TOPLEFT", 14, -38)
    shellNotice:SetPoint("RIGHT", editor, "RIGHT", -14, 0)
    shellNotice:SetJustifyH("LEFT")
    shellNotice:SetTextColor(1.00, 0.82, 0.26, 1.00)
    editor.__bootstrapShellNotice = shellNotice
  end
  if shellNotice then
    shellNotice:SetText("Some editor modules are unavailable. LidCouncil loaded the editor with reduced functionality.")
  end

  local pageTopOffset = -96
  local tabDefs = {
    { key = "Profiles", label = "Profile", pageField = "profilesPage" },
    { key = "Panels", label = "Session", pageField = "panelsPage" },
    { key = "LiveBoard", label = "Live Board", pageField = "liveBoardPage" },
    { key = "Backgrounds", label = "Loot List", pageField = "backgroundsPage" },
    { key = "LootPresets", label = "Loot Presets", pageField = "lootPresetsPage" },
    { key = "UI", label = "UI", pageField = "uiPage" },
    { key = "Tutorial", label = "Tutorial", pageField = "tutorialPage" },
    { key = "About", label = "About", pageField = "aboutPage" },
  }

  local shell = {}
  editor.__bootstrapPages = editor.__bootstrapPages or {}
  local previousButton = nil
  for _, def in ipairs(tabDefs) do
    local buttonKey = "__bootstrapTab_" .. def.key
    local button = editor[buttonKey]
    if not button then
      button = CreateFrame("Button", nil, editor, "UIPanelButtonTemplate")
      button:SetSize(108, 22)
      if previousButton then
        button:SetPoint("TOPLEFT", previousButton, "TOPRIGHT", 6, 0)
      else
        button:SetPoint("TOPLEFT", 14, -66)
      end
      editor[buttonKey] = button
    end
    button:SetText(def.label)
    previousButton = button
    editor.mainTabs[def.key] = button

    local page = editor.__bootstrapPages[def.key]
    if not page then
      page = CreateFrame("Frame", nil, editor)
      page:SetPoint("TOPLEFT", 8, pageTopOffset)
      page:SetPoint("BOTTOMRIGHT", -8, 8)
      page:Hide()
      editor.__bootstrapPages[def.key] = page
    end
    shell[def.pageField] = page
  end

  local function ShowPage(which)
    for key, page in pairs(editor.__bootstrapPages or {}) do
      if key == which then
        page:Show()
      else
        page:Hide()
      end
    end
    editor.currentPage = which
    for key, button in pairs(editor.mainTabs or {}) do
      if button and button.SetEnabled then
        button:SetEnabled(key ~= which)
      end
    end
    RequestTopLevelEditorPageRefresh(editor, which)
  end

  for _, def in ipairs(tabDefs) do
    local button = editor.mainTabs[def.key]
    if button then
      button:SetScript("OnClick", function()
        ShowPage(def.key)
      end)
    end
  end

  editor.ShowPage = ShowPage
  editor.UpdateUILayout = Noop
  editor.UpdateScrollLayout = Noop
  editor.profilesTab = editor.mainTabs.Profiles
  editor.panelsTab = editor.mainTabs.Panels
  editor.liveBoardTab = editor.mainTabs.LiveBoard
  editor.backgroundsTab = editor.mainTabs.Backgrounds
  editor.lootPresetsTab = editor.mainTabs.LootPresets
  editor.uiTab = editor.mainTabs.UI
  editor.tutorialTab = editor.mainTabs.Tutorial
  editor.aboutTab = editor.mainTabs.About
  return shell
end

local EDITOR_CREATE_DEPS = {
  RootDB = RootDB,
  DB = DB,
  GetDebugStore = GetDebugStore,
  ReportEditorRuntimeError = ReportEditorRuntimeError,
  SetupEditorFrameShell = type(SetupEditorFrameShell) == "function" and SetupEditorFrameShell or BuildFallbackEditorFrameShell,
  BindEditorTheme = type(BindEditorTheme) == "function" and BindEditorTheme or Noop,
  ApplyFrameSkin = ApplyFrameSkin,
  ApplyEditorState = ApplyEditorState,
  ApplyEditorScale = ApplyEditorScale,
  SaveEditorState = SaveEditorState,
  ApplyEditorLogo = ApplyEditorLogo,
  SetAllUnlocked = SetAllUnlocked,
  GetPanelsUnlockedState = GetPanelsUnlockedState,
  NudgeSelectedPanel = NudgeSelectedPanel,
  CreatePurpleOutline = CreatePurpleOutline,
  ApplySkinPreset = ApplySkinPreset,
  ApplyHeaderBackground = ApplyHeaderBackground,
  EnsureGradientTables = EnsureGradientTables,
  LISTS_PER_PAGE = LISTS_PER_PAGE,
  GetSortedPanelNames = GetSortedPanelNames,
  GetListPageForValue = GetListPageForValue,
  ClampListPage = ClampListPage,
  MakeListButton = MakeListButton,
  MakeSimpleListButton = MakeSimpleListButton,
  MakeProfileButton = MakeProfileButton,
  SelectPanel = SelectPanel,
  UpdatePagerControls = UpdatePagerControls,
  ListBackgroundCategories = ListBackgroundCategories,
  FindCategoryIndex = FindCategoryIndex,
  FindBackgroundCategoryGroupIndex = FindBackgroundCategoryGroupIndex,
  EnsureBackgroundCategoryGroups = EnsureBackgroundCategoryGroups,
  BuildVisibleBackgroundCategoryRows = BuildVisibleBackgroundCategoryRows,
  GetBackgroundCategoryFocusKey = GetBackgroundCategoryFocusKey,
  ToggleBackgroundCategoryGroupCollapsed = ToggleBackgroundCategoryGroupCollapsed,
  ConfigureBackgroundCategoryGroupButton = ConfigureBackgroundCategoryGroupButton,
  ClearBackgroundCategoryDragState = ClearBackgroundCategoryDragState,
  BeginBackgroundCategoryGroupDrag = BeginBackgroundCategoryGroupDrag,
  BeginBackgroundCategoryDrag = BeginBackgroundCategoryDrag,
  SelectBackground = SelectBackground,
  GetSortedBackgroundNames = GetSortedBackgroundNames,
  ListBackgrounds = ListBackgrounds,
  FindProfileGroupIndex = function(...)
    return GetEditorProfileHelpers().FindProfileGroupIndex(...)
  end,
  EnsureProfileGroups = function(...)
    return GetEditorProfileHelpers().EnsureProfileGroups(...)
  end,
  BuildVisibleProfileRows = function(...)
    return GetEditorProfileHelpers().BuildVisibleProfileRows(...)
  end,
  GetProfileFocusKey = function(...)
    return GetEditorProfileHelpers().GetProfileFocusKey(...)
  end,
  ToggleProfileGroupCollapsed = function(...)
    return GetEditorProfileHelpers().ToggleProfileGroupCollapsed(...)
  end,
  ConfigureProfileGroupButton = ConfigureProfileGroupButton,
  BeginProfileGroupDrag = BeginProfileGroupDrag,
  ClearProfileGroupDragState = ClearProfileGroupDragState,
  InvalidateSortedProfileNames = function(...)
    return GetEditorProfileHelpers().InvalidateSortedProfileNames(...)
  end,
  InvalidateSortedPanelNames = InvalidateSortedPanelNames,
  ApplyDropdownLimits = ApplyDropdownLimits,
  ADDON_VERSION = ADDON_VERSION,
  WOW_CLIENT_VERSION = WOW_CLIENT_VERSION,
  LOGO_TARGET_W = LOGO_TARGET_W,
  LOGO_TARGET_H = LOGO_TARGET_H,
  LogSilent = LogSilent,
}

local function CreateEditor()
  local deps = EDITOR_CREATE_DEPS
  local RootDB = deps.RootDB
  local DB = deps.DB
  local GetDebugStore = deps.GetDebugStore
  local ReportEditorRuntimeError = deps.ReportEditorRuntimeError
  local SetupEditorFrameShell = deps.SetupEditorFrameShell
  local BindEditorTheme = deps.BindEditorTheme
  local ApplyFrameSkin = deps.ApplyFrameSkin
  local ApplyEditorState = deps.ApplyEditorState
  local ApplyEditorScale = deps.ApplyEditorScale
  local SaveEditorState = deps.SaveEditorState
  local ApplyEditorLogo = deps.ApplyEditorLogo
  local SetAllUnlocked = deps.SetAllUnlocked
  local GetPanelsUnlockedState = deps.GetPanelsUnlockedState
  local NudgeSelectedPanel = deps.NudgeSelectedPanel
  local CreatePurpleOutline = deps.CreatePurpleOutline
  local ApplySkinPreset = deps.ApplySkinPreset
  local ApplyHeaderBackground = deps.ApplyHeaderBackground
  local EnsureGradientTables = deps.EnsureGradientTables
  local LISTS_PER_PAGE = deps.LISTS_PER_PAGE
  local GetSortedPanelNames = deps.GetSortedPanelNames
  local GetListPageForValue = deps.GetListPageForValue
  local ClampListPage = deps.ClampListPage
  local MakeListButton = deps.MakeListButton
  local MakeSimpleListButton = deps.MakeSimpleListButton
  local MakeProfileButton = deps.MakeProfileButton
  local SelectPanel = deps.SelectPanel
  local UpdatePagerControls = deps.UpdatePagerControls
  local ListBackgroundCategories = deps.ListBackgroundCategories
  local FindCategoryIndex = deps.FindCategoryIndex
  local FindBackgroundCategoryGroupIndex = deps.FindBackgroundCategoryGroupIndex
  local EnsureBackgroundCategoryGroups = deps.EnsureBackgroundCategoryGroups
  local BuildVisibleBackgroundCategoryRows = deps.BuildVisibleBackgroundCategoryRows
  local GetBackgroundCategoryFocusKey = deps.GetBackgroundCategoryFocusKey
  local ToggleBackgroundCategoryGroupCollapsed = deps.ToggleBackgroundCategoryGroupCollapsed
  local ConfigureBackgroundCategoryGroupButton = deps.ConfigureBackgroundCategoryGroupButton
  local ClearBackgroundCategoryDragState = deps.ClearBackgroundCategoryDragState
  local BeginBackgroundCategoryGroupDrag = deps.BeginBackgroundCategoryGroupDrag
  local BeginBackgroundCategoryDrag = deps.BeginBackgroundCategoryDrag
  local SelectBackground = deps.SelectBackground
  local GetSortedBackgroundNames = deps.GetSortedBackgroundNames
  local ListBackgrounds = deps.ListBackgrounds
  local FindProfileGroupIndex = deps.FindProfileGroupIndex
  local EnsureProfileGroups = deps.EnsureProfileGroups
  local BuildVisibleProfileRows = deps.BuildVisibleProfileRows
  local GetProfileFocusKey = deps.GetProfileFocusKey
  local ToggleProfileGroupCollapsed = deps.ToggleProfileGroupCollapsed
  local ConfigureProfileGroupButton = deps.ConfigureProfileGroupButton
  local BeginProfileGroupDrag = deps.BeginProfileGroupDrag
  local ClearProfileGroupDragState = deps.ClearProfileGroupDragState
  local InvalidateSortedProfileNames = deps.InvalidateSortedProfileNames
  local InvalidateSortedPanelNames = deps.InvalidateSortedPanelNames
  local ApplyDropdownLimits = deps.ApplyDropdownLimits
  local ADDON_VERSION = deps.ADDON_VERSION
  local WOW_CLIENT_VERSION = deps.WOW_CLIENT_VERSION
  local LOGO_TARGET_W = deps.LOGO_TARGET_W
  local LOGO_TARGET_H = deps.LOGO_TARGET_H
  local LogSilent = deps.LogSilent

  if _G.LIDCOUNCIL_Editor and _G.LIDCOUNCIL_Editor.__lidCouncilEditor then
    editor = _G.LIDCOUNCIL_Editor
    return
  end
  if editor and editor.GetName and editor:GetName() == "LIDCOUNCIL_Editor" then return end

  editor = CreateFrame("Frame", "LIDCOUNCIL_Editor", UIParent, "BackdropTemplate")
  editor.__lidCouncilEditor = true
  _G.LIDCOUNCIL_Editor = editor
  editor:SetFrameStrata("DIALOG")
  editor:SetClampedToScreen(true)
  editor:SetClipsChildren(true)
  editor:Hide()

  local WORKFLOW_REFRESH_PAGE_ALIASES = {
    about = "About",
    backgrounds = "Backgrounds",
    liveboard = "LiveBoard",
    panels = "Panels",
    profiles = "Profiles",
    ui = "UI",
  }
  local VALID_WORKFLOW_LOOT_SESSION_SECTIONS = {
    AUTOPASS = true,
    CURRENT = true,
    HISTORY = true,
    ROLESIM = true,
    SYNCMGMT = true,
  }
  local function IsWorkflowRefreshHandlerCallable(handler)
    return type(handler) == "function" and handler ~= Noop
  end
  local function NormalizeWorkflowRefreshPages(pageTargets)
    if type(pageTargets) ~= "table" then
      return nil
    end
    local normalized = {}
    for pageName, enabled in pairs(pageTargets) do
      if enabled then
        local resolvedPage = TrimText(pageName)
        if resolvedPage ~= "" then
          local canonicalPage = WORKFLOW_REFRESH_PAGE_ALIASES[string.lower(resolvedPage)] or resolvedPage
          normalized[canonicalPage] = true
        end
      end
    end
    return next(normalized) ~= nil and normalized or nil
  end
  local function NormalizeWorkflowLootSessionSections(sectionTargets)
    if type(sectionTargets) ~= "table" then
      return nil
    end
    local normalized = {}
    for sectionName, enabled in pairs(sectionTargets) do
      if enabled then
        local resolvedSection = string.upper(TrimText(sectionName))
        if VALID_WORKFLOW_LOOT_SESSION_SECTIONS[resolvedSection] == true then
          normalized[resolvedSection] = true
        end
      end
    end
    return next(normalized) ~= nil and normalized or nil
  end
  local function BuildWorkflowLootSessionSectionTargets(targetEditor, sectionTargets)
    local normalizedTargets = NormalizeWorkflowLootSessionSections(
      type(sectionTargets) == "table" and sectionTargets or nil
    )
    if normalizedTargets ~= nil then
      return normalizedTargets
    end

    local resolvedSection = string.upper(TrimText(sectionTargets))
    if VALID_WORKFLOW_LOOT_SESSION_SECTIONS[resolvedSection] == true then
      return {
        [resolvedSection] = true,
      }
    end

    local fallbackSection = string.upper(TrimText(type(targetEditor) == "table" and targetEditor.lootSessionSection or ""))
    if VALID_WORKFLOW_LOOT_SESSION_SECTIONS[fallbackSection] ~= true then
      fallbackSection = "CURRENT"
    end
    return {
      [fallbackSection] = true,
    }
  end

  local function RequestWorkflowRefreshInternal(targetEditor, opts)
    if type(targetEditor) ~= "table" then
      return false
    end
    opts = type(opts) == "table" and opts or {}

    local refreshPages = NormalizeWorkflowRefreshPages(opts.refreshPages) or {}
    local lootSessionSections = NormalizeWorkflowLootSessionSections(opts.lootSessionSections)
    if lootSessionSections ~= nil then
      refreshPages.Panels = true
    end

    local refreshOpts = {}
    if opts.refreshAllLoot == true then
      refreshOpts.refreshAllLoot = true
    end
    if opts.refreshAbout == true then
      refreshOpts.refreshAbout = true
    end
    if opts.refreshHiddenPages == true then
      refreshOpts.refreshHiddenPages = true
    end
    if next(refreshPages) ~= nil then
      refreshOpts.refreshPages = refreshPages
    end
    if lootSessionSections ~= nil then
      refreshOpts.lootSessionSections = lootSessionSections
    end

    -- Comm events can arrive while a section is rebuilding. Do not lose the
    -- update: merge it and retry after the active refresh has completed.
    if targetEditor.__refreshing then
      local pending = type(targetEditor.__lidPendingWorkflowRefresh) == "table"
        and targetEditor.__lidPendingWorkflowRefresh
        or {
          refreshPages = {},
          lootSessionSections = {},
        }
      pending.refreshAllLoot = pending.refreshAllLoot == true or refreshOpts.refreshAllLoot == true
      pending.refreshAbout = pending.refreshAbout == true or refreshOpts.refreshAbout == true
      pending.refreshHiddenPages = pending.refreshHiddenPages == true or refreshOpts.refreshHiddenPages == true
      for pageKey, enabled in pairs(type(refreshOpts.refreshPages) == "table" and refreshOpts.refreshPages or {}) do
        if enabled == true then
          pending.refreshPages[pageKey] = true
        end
      end
      for sectionKey, enabled in pairs(type(refreshOpts.lootSessionSections) == "table" and refreshOpts.lootSessionSections or {}) do
        if enabled == true then
          pending.lootSessionSections[sectionKey] = true
        end
      end
      targetEditor.__lidPendingWorkflowRefresh = pending
      if pending.scheduled ~= true and type(C_Timer) == "table" and type(C_Timer.After) == "function" then
        pending.scheduled = true
        C_Timer.After(0.05, function()
          local queued = targetEditor.__lidPendingWorkflowRefresh
          targetEditor.__lidPendingWorkflowRefresh = nil
          if type(queued) == "table" then
            queued.scheduled = nil
            RequestWorkflowRefreshInternal(targetEditor, queued)
          end
        end)
      end
      return true
    end

    if IsWorkflowRefreshHandlerCallable(targetEditor.RefreshLootWorkflowSections) then
      if next(refreshOpts) ~= nil then
        targetEditor:RefreshLootWorkflowSections(refreshOpts)
      else
        targetEditor:RefreshLootWorkflowSections()
      end
      return true
    end
    if IsWorkflowRefreshHandlerCallable(targetEditor.RefreshLootSessionPage)
      and (
        refreshOpts.refreshAllLoot == true
        or lootSessionSections ~= nil
        or (type(refreshOpts.refreshPages) == "table" and refreshOpts.refreshPages.Panels == true)
      )
    then
      targetEditor:RefreshLootSessionPage(next(refreshOpts) ~= nil and refreshOpts or nil)
      return true
    end
    if IsWorkflowRefreshHandlerCallable(targetEditor.RefreshLootLiveBoardPage)
      and type(refreshOpts.refreshPages) == "table"
      and refreshOpts.refreshPages.LiveBoard == true
    then
      targetEditor:RefreshLootLiveBoardPage()
      return true
    end
    if refreshOpts.refreshAbout == true and IsWorkflowRefreshHandlerCallable(targetEditor.RefreshAbout) then
      targetEditor:RefreshAbout()
      return true
    end
    if IsWorkflowRefreshHandlerCallable(targetEditor.Refresh) then
      targetEditor:Refresh()
      return true
    end
    return false
  end
  local function RequestTopLevelEditorPageRefresh(targetEditor, which)
    local resolvedPage = TrimText(which)
    local refreshPages = nil
    if resolvedPage == "Profiles" or resolvedPage == "Panels" or resolvedPage == "LiveBoard" or resolvedPage == "Backgrounds" or resolvedPage == "LootPresets" then
      refreshPages = {
        [resolvedPage] = true,
      }
    end
    if refreshPages ~= nil or resolvedPage == "About" then
      return RequestWorkflowRefreshInternal(targetEditor, {
        refreshPages = refreshPages,
        refreshAbout = resolvedPage == "About",
      })
    end
    return false
  end
  local function RequestEditorAboutRefresh(targetEditor)
    return RequestWorkflowRefreshInternal(targetEditor, {
      refreshAbout = true,
    })
  end
  INTERNAL_API.LIDCOUNCIL_IsEditorWorkflowRefreshHandlerCallable_Impl = IsWorkflowRefreshHandlerCallable
  INTERNAL_API.LIDCOUNCIL_NormalizeEditorWorkflowRefreshPages_Impl = NormalizeWorkflowRefreshPages
  INTERNAL_API.LIDCOUNCIL_NormalizeEditorLootSessionSections_Impl = NormalizeWorkflowLootSessionSections
  INTERNAL_API.LIDCOUNCIL_BuildEditorLootSessionSectionTargets_Impl = BuildWorkflowLootSessionSectionTargets
  INTERNAL_API.LIDCOUNCIL_RequestEditorWorkflowRefresh_Impl = RequestWorkflowRefreshInternal
  INTERNAL_API.LIDCOUNCIL_RequestEditorPageRefresh_Impl = RequestTopLevelEditorPageRefresh
  INTERNAL_API.LIDCOUNCIL_RequestEditorAboutRefresh_Impl = RequestEditorAboutRefresh

  editor.RequestWorkflowRefresh = function(selfOrOpts, opts)
    local targetEditor = type(selfOrOpts) == "table" and selfOrOpts.__lidCouncilEditor == true
      and selfOrOpts
      or editor
    local resolvedOpts = targetEditor == selfOrOpts and opts or selfOrOpts
    return RequestWorkflowRefreshInternal(targetEditor, resolvedOpts)
  end
  editor.RequestLootSessionSectionRefresh = function(selfOrSectionTargets, sectionTargetsOrRefreshPages, refreshPages)
    local targetEditor = type(selfOrSectionTargets) == "table" and selfOrSectionTargets.__lidCouncilEditor == true
      and selfOrSectionTargets
      or editor
    local resolvedSectionTargetsInput = targetEditor == selfOrSectionTargets
      and sectionTargetsOrRefreshPages
      or selfOrSectionTargets
    local resolvedRefreshPages = targetEditor == selfOrSectionTargets
      and refreshPages
      or sectionTargetsOrRefreshPages
    local resolvedSectionTargets = BuildWorkflowLootSessionSectionTargets(targetEditor, resolvedSectionTargetsInput)
    return RequestWorkflowRefreshInternal(targetEditor, {
      refreshPages = resolvedRefreshPages,
      lootSessionSections = resolvedSectionTargets,
    })
  end
  INTERNAL_API.LIDCOUNCIL_RequestEditorLootSessionSectionRefresh_Impl = function(targetEditor, sectionTargets, refreshPages)
    local resolvedEditor = type(targetEditor) == "table" and targetEditor.__lidCouncilEditor == true
      and targetEditor
      or editor
    return resolvedEditor.RequestLootSessionSectionRefresh(resolvedEditor, sectionTargets, refreshPages)
  end

  local function DisplayProfileNameLocal(name)
    if not name or name == "" then return "(none)" end
    if name == "Default" then return "No active Profile :(" end
    return name
  end

  local buildTutorialPage = _G.LIDCOUNCIL_BuildTutorialPage
  local shellDeps = {
    RootDB = RootDB,
    ApplyFrameSkin = ApplyFrameSkin,
    ApplyEditorState = ApplyEditorState,
    ApplyEditorScale = ApplyEditorScale,
    SaveEditorState = SaveEditorState,
    ApplyEditorLogo = ApplyEditorLogo,
    SetAllUnlocked = SetAllUnlocked,
    GetPanelsUnlockedState = GetPanelsUnlockedState,
    NudgeSelectedPanel = NudgeSelectedPanel,
    CreatePurpleOutline = CreatePurpleOutline,
    DisplayProfileName = DisplayProfileNameLocal,
    BuildTutorialPage = buildTutorialPage,
    ADDON_VERSION = ADDON_VERSION,
    WOW_CLIENT_VERSION = WOW_CLIENT_VERSION,
    LOGO_TARGET_W = LOGO_TARGET_W,
    LOGO_TARGET_H = LOGO_TARGET_H,
    LogSilent = LogSilent,
  }
  local shell = nil
  local shellOk, shellResult = pcall(SetupEditorFrameShell, editor, shellDeps)
  if shellOk and type(shellResult) == "table" then
    shell = shellResult
  else
    if not shellOk then
      RecordBootstrapIssue("Editor Shell", "Editor frame shell failed: " .. tostring(shellResult))
    else
      RecordBootstrapIssue("Editor Shell", "Editor frame shell returned no shell data.")
    end
    shell = BuildFallbackEditorFrameShell(editor, shellDeps)
  end

  local panelsPage = shell.panelsPage
  local liveBoardPage = shell.liveBoardPage
  local profilesPage = shell.profilesPage
  local backgroundsPage = shell.backgroundsPage
  local lootPresetsPage = shell.lootPresetsPage
  local uiPage = shell.uiPage
  local tutorialPage = shell.tutorialPage
  local aboutPage = shell.aboutPage
  editor.allowKeyboardNudging = false

  if BindEditorTheme == Noop then
    RecordBootstrapIssue("Editor Theme", "Missing editor theme binder.")
  end
  local themeOk, themeErr = pcall(BindEditorTheme, editor, {
    RootDB = RootDB,
    ApplySkinPreset = ApplySkinPreset,
    ApplyEditorLogo = ApplyEditorLogo,
    ApplyHeaderBackground = ApplyHeaderBackground,
  })
  if not themeOk then
    RecordBootstrapIssue("Editor Theme", "Editor theme binding failed: " .. tostring(themeErr))
  end
 
  local wireEditorRefreshSections = INTERNAL_API.LIDCOUNCIL_WireEditorRefreshSections
  if type(wireEditorRefreshSections) == "function" then
    wireEditorRefreshSections(editor, {
      RootDB = RootDB,
      DB = DB,
      GetDebugStore = GetDebugStore,
      ReportEditorRuntimeError = ReportEditorRuntimeError,
      GetPanelsUnlockedState = GetPanelsUnlockedState,
      EnsureGradientTables = EnsureGradientTables,
      SetDropdownSelection = SetDropdownSelection,
      DisplayProfileName = DisplayProfileNameLocal,
      GetEnabledLootProfileName = GetEnabledLootProfileName,
      GetCharacterKey = GetCharacterKey,
      ADDON_VERSION = ADDON_VERSION,
      WOW_CLIENT_VERSION = WOW_CLIENT_VERSION,
      LISTS_PER_PAGE = LISTS_PER_PAGE,
      GetSortedPanelNames = GetSortedPanelNames,
      GetListPageForValue = GetListPageForValue,
      ClampListPage = ClampListPage,
      MakeListButton = MakeListButton,
      MakeSimpleListButton = MakeSimpleListButton,
      MakeProfileButton = MakeProfileButton,
      SelectPanel = SelectPanel,
      UpdatePagerControls = UpdatePagerControls,
      ListBackgroundCategories = ListBackgroundCategories,
      FindCategoryIndex = FindCategoryIndex,
      FindBackgroundCategoryGroupIndex = FindBackgroundCategoryGroupIndex,
      EnsureBackgroundCategoryGroups = EnsureBackgroundCategoryGroups,
      BuildVisibleBackgroundCategoryRows = BuildVisibleBackgroundCategoryRows,
      GetBackgroundCategoryFocusKey = GetBackgroundCategoryFocusKey,
      ToggleBackgroundCategoryGroupCollapsed = ToggleBackgroundCategoryGroupCollapsed,
      ConfigureBackgroundCategoryGroupButton = ConfigureBackgroundCategoryGroupButton,
      BeginBackgroundCategoryGroupDrag = BeginBackgroundCategoryGroupDrag,
      BeginBackgroundCategoryDrag = BeginBackgroundCategoryDrag,
      SelectBackground = SelectBackground,
      GetSortedBackgroundNames = GetSortedBackgroundNames,
      ListBackgrounds = ListBackgrounds,
      FindProfileGroupIndex = FindProfileGroupIndex,
      EnsureProfileGroups = EnsureProfileGroups,
      BuildVisibleProfileRows = BuildVisibleProfileRows,
      GetProfileFocusKey = GetProfileFocusKey,
      ToggleProfileGroupCollapsed = ToggleProfileGroupCollapsed,
      ConfigureProfileGroupButton = ConfigureProfileGroupButton,
      BeginProfileGroupDrag = BeginProfileGroupDrag,
      InvalidateSortedProfileNames = InvalidateSortedProfileNames,
      InvalidateSortedPanelNames = InvalidateSortedPanelNames,
      GetBackgroundPath = GetBackgroundPath,
      CreatePurpleOutline = CreatePurpleOutline,
      GetSelectedPanelName = GetSelectedPanelName,
      GetSelectedBackgroundName = GetSelectedBackgroundName,
      SetSelectedBackgroundName = function(value)
        selectedBackgroundName = value
      end,
      GetSelectedBackgroundCategory = GetSelectedBackgroundCategory,
      SetSelectedBackgroundCategory = function(value)
        selectedBackgroundCategory = value
      end,
      GetSelectedBackgroundCategoryGroup = function()
        return selectedBackgroundCategoryGroup
      end,
      SetSelectedBackgroundCategoryGroup = function(value)
        selectedBackgroundCategoryGroup = value
      end,
    })
  else
    RecordBootstrapIssue("Editor Refresh", "Missing editor refresh section wiring.")
    editor.Refresh = Noop
    editor.RefreshLootWorkflowSections = Noop
  end

  local buildLootProfilesPage = _G.LIDCOUNCIL_BuildLootProfilesPage
  local buildLootSessionPage = _G.LIDCOUNCIL_BuildLootSessionPage
  local buildLootLiveBoardPage = _G.LIDCOUNCIL_BuildLootLiveBoardPage
  local buildLootListPage = _G.LIDCOUNCIL_BuildLootListPage
  local buildLootPresetsPage = _G.LIDCOUNCIL_BuildLootPresetsPage
  local buildUIPage = _G.LIDCOUNCIL_BuildUIPage
  local buildAboutPage = _G.LIDCOUNCIL_BuildAboutPage
  if type(buildTutorialPage) ~= "function" then
    BuildUnavailablePage(tutorialPage, "Tutorial", "Missing tutorial page builder.")
  end
  local function SafeBuildPage(label, pageFrame, fn, ...)
    if type(fn) ~= "function" then
      RecordBootstrapIssue("Editor Page", "Missing page builder for " .. tostring(label) .. ".")
      BuildUnavailablePage(pageFrame, label, "Missing page builder.")
      return
    end
    local ok, err = pcall(fn, ...)
    if ok then
      return
    end
    if type(LogSilent) == "function" then
      LogSilent("Page build failed for " .. tostring(label) .. ": " .. tostring(err))
    end
    if type(Print) == "function" then
      Print("Page build failed for " .. tostring(label) .. ". See Lua errors for details.")
    end
    BuildUnavailablePage(pageFrame, label, err)
  end

  SafeBuildPage("Profiles", profilesPage, buildLootProfilesPage, editor, profilesPage)
  SafeBuildPage("Session", panelsPage, buildLootSessionPage, editor, panelsPage)
  SafeBuildPage("Live Board", liveBoardPage, buildLootLiveBoardPage, editor, liveBoardPage)
  SafeBuildPage("Loot List", backgroundsPage, buildLootListPage, editor, backgroundsPage)
  SafeBuildPage("Loot Presets", lootPresetsPage, buildLootPresetsPage, editor, lootPresetsPage)
  SafeBuildPage("UI Settings", uiPage, buildUIPage, editor, uiPage)
  SafeBuildPage("About", aboutPage, buildAboutPage, editor, aboutPage)
  aboutPage.__contentHeight = 600

  if editor.ShowPage then
    editor.ShowPage("Profiles")
  end
end

INTERNAL_API.LIDCOUNCIL_GetEditorUiHelpersDeps_Impl = function()
  return {
    RootDB = RootDB,
    Compat = Compat,
    LISTS_PER_PAGE = LISTS_PER_PAGE,
    GetEditor = function()
      return editor
    end,
  }
end

INTERNAL_API.LIDCOUNCIL_GetEditorPanelManagementDeps_Impl = function()
  return {
    RootDB = RootDB,
    DB = DB,
    DeepCopy = DeepCopy,
    Print = Print,
    LogSilent = LogSilent,
    RebuildAllPanels = RebuildAllPanels,
    TrimName = function(...)
      return TrimName(...)
    end,
    ClampNameLen = function(...)
      return ClampNameLen(...)
    end,
    GetEditor = function()
      return editor
    end,
    GetSelectedPanelName = function()
      return selectedPanelName
    end,
    SetSelectedPanelName = function(value)
      selectedPanelName = value
    end,
    MAX_PANEL_NAME = MAX_PANEL_NAME,
    Frames = frames,
  }
end

INTERNAL_API.LIDCOUNCIL_GetEditorProfileDragDeps_Impl = function()
  return {
    TrimName = function(...)
      return TrimName(...)
    end,
    Print = Print,
    CreatePurpleOutline = CreatePurpleOutline,
    GetEditor = function()
      return editor
    end,
    AssignProfileToGroup = function(...)
      return GetEditorProfileHelpers().AssignProfileToGroup(...)
    end,
  }
end

INTERNAL_API.LIDCOUNCIL_GetEditorBackgroundManagementDeps_Impl = function()
  return {
    RootDB = RootDB,
    Print = Print,
    LogSilent = LogSilent,
    TrimName = function(...)
      return TrimName(...)
    end,
    ClampNameLen = function(...)
      return ClampNameLen(...)
    end,
    CreatePurpleOutline = CreatePurpleOutline,
    GetEditor = function()
      return editor
    end,
    GetSelectedBackgroundName = function()
      return selectedBackgroundName
    end,
    SetSelectedBackgroundName = function(value)
      selectedBackgroundName = value
    end,
    GetSelectedBackgroundCategory = function()
      return selectedBackgroundCategory
    end,
    SetSelectedBackgroundCategory = function(value)
      selectedBackgroundCategory = value
    end,
    GetSelectedBackgroundCategoryGroup = function()
      return selectedBackgroundCategoryGroup
    end,
    SetSelectedBackgroundCategoryGroup = function(value)
      selectedBackgroundCategoryGroup = value
    end,
    MAX_BACKGROUND_NAME = MAX_BACKGROUND_NAME,
    MAX_BG_CATEGORY_NAME = MAX_BG_CATEGORY_NAME,
    MAX_BG_CATEGORY_GROUP_NAME = MAX_BG_CATEGORY_GROUP_NAME,
  }
end

INTERNAL_API.LIDCOUNCIL_GetEditorPopupDialogDeps_Impl = function()
  return {
    RootDB = RootDB,
    Print = Print,
    EnsureDefaults = EnsureDefaults,
    RebuildAllPanels = RebuildAllPanels,
    GetEditorProfileHelpers = GetEditorProfileHelpers,
    GetEditor = function()
      return editor
    end,
    GetSelectedPanelName = function()
      return selectedPanelName
    end,
    GetSelectedBackgroundName = function()
      return selectedBackgroundName
    end,
    GetSelectedBackgroundCategory = function()
      return selectedBackgroundCategory
    end,
    GetSelectedBackgroundCategoryGroup = function()
      return selectedBackgroundCategoryGroup
    end,
    RenameSelectedPanel = function(...)
      return RenameSelectedPanel(...)
    end,
    CopySelectedPanelToProfile = function(...)
      return CopySelectedPanelToProfile(...)
    end,
    DeleteSelectedPanel = function(...)
      return DeleteSelectedPanel(...)
    end,
    CreateNewPanelNamed = function(...)
      return CreateNewPanelNamed(...)
    end,
    CreateBackgroundNamed = function(...)
      return CreateBackgroundNamed(...)
    end,
    RenameBackground = function(...)
      return RenameBackground(...)
    end,
    DeleteBackground = function(...)
      return DeleteBackground(...)
    end,
    CreateBackgroundCategoryNamed = function(...)
      return CreateBackgroundCategoryNamed(...)
    end,
    DeleteBackgroundCategory = function(...)
      return DeleteBackgroundCategory(...)
    end,
    RenameBackgroundCategory = function(...)
      return RenameBackgroundCategory(...)
    end,
    CreateBackgroundCategoryGroupNamed = function(...)
      return CreateBackgroundCategoryGroupNamed(...)
    end,
    RenameBackgroundCategoryGroup = function(...)
      return RenameBackgroundCategoryGroup(...)
    end,
    DeleteBackgroundCategoryGroup = function(...)
      return DeleteBackgroundCategoryGroup(...)
    end,
    TrimName = function(...)
      return TrimName(...)
    end,
    MAX_PANEL_NAME = MAX_PANEL_NAME,
    MAX_PROFILE_NAME = MAX_PROFILE_NAME,
    MAX_PROFILE_GROUP_NAME = MAX_PROFILE_GROUP_NAME,
    MAX_BACKGROUND_NAME = MAX_BACKGROUND_NAME,
    MAX_BG_CATEGORY_NAME = MAX_BG_CATEGORY_NAME,
    MAX_BG_CATEGORY_GROUP_NAME = MAX_BG_CATEGORY_GROUP_NAME,
  }
end

INTERNAL_API.LIDCOUNCIL_GetEditorFloatingWindowDeps_Impl = function()
  return {
    GetDebugStore = GetDebugStore,
    GetEditor = function()
      return editor
    end,
    ApplyFrameSkin = ApplyFrameSkin,
    Print = Print,
  }
end

local API = _G.LIDCOUNCIL_API
if type(API) ~= "table" then
  API = {}
  _G.LIDCOUNCIL_API = API
  RecordBootstrapIssue("Editor Bootstrap", "Missing API table. Created fallback API registry.")
end

local function PublishApi(name, value, opts)
  API[name] = value
  if type(opts) == "table" and opts.global == false then
    _G[name] = nil
    return
  end
  _G[name] = value
end

PublishApi("LIDCOUNCIL_CreateEditor", CreateEditor, { global = false })
PublishApi("LIDCOUNCIL_GetBootstrapIssueText", GetBootstrapIssueText)
PublishApi("LIDCOUNCIL_OpenColorPickerRGBOnly", OpenColorPickerRGBOnly, { global = false })
PublishApi("LIDCOUNCIL_OpenColorPickerRGBOnlyOnAccept", OpenColorPickerRGBOnlyOnAccept, { global = false })
PublishApi("LIDCOUNCIL_ApplyFrameSkin", ApplyFrameSkin, { global = false })
PublishApi("LIDCOUNCIL_BuildBackgroundList", BuildBackgroundList, { global = false })
PublishApi("LIDCOUNCIL_GetBackgroundPath", GetBackgroundPath, { global = false })
PublishApi("LIDCOUNCIL_MakeYellowSubHeader", MakeYellowSubHeader, { global = false })
PublishApi("LIDCOUNCIL_MakeSlider", MakeSlider, { global = false })
PublishApi("LIDCOUNCIL_CARD_W", CARD_W, { global = false })
PublishApi("LIDCOUNCIL_CARD_H", CARD_H, { global = false })
PublishApi("LIDCOUNCIL_ApplyEditorState", ApplyEditorState, { global = false })
PublishApi("LIDCOUNCIL_ApplyEditorScale", ApplyEditorScale, { global = false })
PublishApi("LIDCOUNCIL_SwitchProfile", function(name)
  return GetEditorProfileHelpers().SwitchProfile(name)
end, { global = false })
PublishApi("LIDCOUNCIL_SelectPanel", SelectPanel, { global = false })
PublishApi("LIDCOUNCIL_GetSelectedPanelName", GetSelectedPanelName, { global = false })
PublishApi("LIDCOUNCIL_GetSelectedBackgroundName", GetSelectedBackgroundName, { global = false })
PublishApi("LIDCOUNCIL_GetSelectedBackgroundCategory", GetSelectedBackgroundCategory, { global = false })

-- ============================================================
