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 GetEditorThemePalette = type(INTERNAL_API.LIDCOUNCIL_GetEditorThemePalette_Impl) == "function"
  and INTERNAL_API.LIDCOUNCIL_GetEditorThemePalette_Impl
  or nil

local function CreateMainTab(parent, previous, def)
  local button = CreateFrame("Button", nil, parent, "UIPanelButtonTemplate")
  button:SetSize(def.width, 22)
  if previous then
    button:SetPoint("LEFT", previous, "RIGHT", 8, 0)
  else
    button:SetPoint("LEFT", 0, 0)
  end
  button:SetText(def.text)
  return button
end

local function CreateRootPage(scrollChild, titleText)
  local page = CreateFrame("Frame", nil, scrollChild)
  page:SetPoint("TOPLEFT", 0, 0)
  page:SetPoint("BOTTOMRIGHT", 0, 0)

  if not titleText then
    return page
  end

  local title = page:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
  title:SetPoint("TOPLEFT", 0, 0)
  title:SetText(titleText)

  local currentLabel = page:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  currentLabel:SetPoint("TOPLEFT", 0, -22)

  return page, title, currentLabel
end

local function SetupEditorFrameShell(editor, deps)
  deps = deps or {}

  local RootDB = deps.RootDB
  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 DisplayProfileName = deps.DisplayProfileName or function(name)
    if not name or name == "" then return "(none)" end
    if name == "Default" then return "No active Profile :(" end
    return tostring(name)
  end
  local BuildTutorialPage = deps.BuildTutorialPage
  local ADDON_VERSION = tostring(deps.ADDON_VERSION or "")
  local WOW_CLIENT_VERSION = tostring(deps.WOW_CLIENT_VERSION or "")
  local LOGO_TARGET_W = tonumber(deps.LOGO_TARGET_W) or 150
  local LOGO_TARGET_H = tonumber(deps.LOGO_TARGET_H) or 120
  local LogSilent = deps.LogSilent

  local warnedResizeOnUpdateFailed = false
  local warnedEditorSizeChangedFailed = false

  local function LogShellFailure(message)
    if type(LogSilent) == "function" then
      LogSilent(message)
    end
  end

  local function ClampEditorSize(width, height)
    local screenW = (UIParent and UIParent.GetWidth and UIParent:GetWidth()) or 1920
    local screenH = (UIParent and UIParent.GetHeight and UIParent:GetHeight()) or 1080
    local minW, minH = 520, 340
    local maxW = math.max(minW, math.floor(screenW - 40))
    local maxH = math.max(minH, math.floor(screenH - 40))

    local clampedW = math.min(math.max(width, minW), maxW)
    local clampedH = math.min(math.max(height, minH), maxH)
    return clampedW, clampedH
  end

  local function AnchorEditorToCurrentTopLeft()
    local left, top = editor:GetLeft(), editor:GetTop()
    if left and top and UIParent then
      editor:ClearAllPoints()
      editor:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", left, top)
    end
  end

  local function SetEditorBackdropVisible(visible)
    if not editor.SetBackdropColor or not editor.SetBackdropBorderColor then
      return
    end
    if visible then
      ApplyFrameSkin(editor)
    else
      editor:SetBackdropColor(0, 0, 0, 0)
      editor:SetBackdropBorderColor(0, 0, 0, 0)
    end
  end

  local function UpdateCollapsedEditorButtonStyle(button)
    if not button then
      return
    end
    local enabled = not button.IsEnabled or button:IsEnabled()
    local hovered = button.__lidEditorCollapsedHovered == true
    local paletteResolver = GetEditorThemePalette
    if type(paletteResolver) ~= "function" and type(INTERNAL_API.LIDCOUNCIL_GetEditorThemePalette_Impl) == "function" then
      paletteResolver = INTERNAL_API.LIDCOUNCIL_GetEditorThemePalette_Impl
    end
    local palette = paletteResolver and paletteResolver() or nil
    local useLootPilot = type(palette) == "table" and (palette.key == "lootpilot" or palette.key == "white_orange")
    local borderColor = enabled and { 0.72, 0.58, 0.20, 0.92 } or { 0.24, 0.24, 0.28, 0.72 }
    local fillColor = hovered and { 0.15, 0.18, 0.24, 0.98 } or { 0.10, 0.12, 0.16, 0.96 }
    local textColor = hovered and { 1.00, 0.90, 0.40, 1.00 } or { 0.94, 0.84, 0.34, 1.00 }
    if useLootPilot then
      borderColor = enabled and { 1.00, 0.88, 0.56, 0.95 } or { 0.42, 0.32, 0.24, 0.72 }
      fillColor = hovered and { 24 / 255, 38 / 255, 62 / 255, 0.98 } or { 7 / 255, 14 / 255, 25 / 255, 0.98 }
      textColor = { 1.00, 1.00, 1.00, 1.00 }
    end
    if not enabled then
      fillColor = useLootPilot and { 4 / 255, 8 / 255, 14 / 255, 0.82 } or { 0.06, 0.06, 0.08, 0.90 }
      textColor = useLootPilot and { 0.74, 0.74, 0.74, 1.00 } or { 0.48, 0.48, 0.54, 1.00 }
    end
    if button.__lidEditorCollapsedBorder then
      button.__lidEditorCollapsedBorder:SetVertexColor(borderColor[1], borderColor[2], borderColor[3], borderColor[4])
    end
    if button.__lidEditorCollapsedFill then
      button.__lidEditorCollapsedFill:SetVertexColor(fillColor[1], fillColor[2], fillColor[3], fillColor[4])
    end
    local fontString = button.GetFontString and button:GetFontString() or nil
    if fontString and fontString.SetTextColor then
      fontString:SetTextColor(textColor[1], textColor[2], textColor[3], textColor[4])
    end
  end

  local function ApplyCollapsedEditorButtonStyle(button)
    if not button or button.__lidEditorCollapsedStyled then
      UpdateCollapsedEditorButtonStyle(button)
      return button
    end
    button.__lidEditorCollapsedStyled = true
    if button.SetNormalTexture then button:SetNormalTexture("") end
    if button.SetPushedTexture then button:SetPushedTexture("") end
    if button.SetHighlightTexture then button:SetHighlightTexture("") end
    if button.SetDisabledTexture then button:SetDisabledTexture("") end
    if button.GetRegions then
      for _, region in ipairs({ button:GetRegions() }) do
        if region and region.GetObjectType and region:GetObjectType() == "Texture" then
          region:SetTexture("")
          region:Hide()
        end
      end
    end
    local border = button:CreateTexture(nil, "BACKGROUND")
    border:SetAllPoints(true)
    border:SetTexture("Interface\\Buttons\\WHITE8x8")
    button.__lidEditorCollapsedBorder = border
    local fill = button:CreateTexture(nil, "BORDER")
    fill:SetPoint("TOPLEFT", 1, -1)
    fill:SetPoint("BOTTOMRIGHT", -1, 1)
    fill:SetTexture("Interface\\Buttons\\WHITE8x8")
    button.__lidEditorCollapsedFill = fill
    if button.HookScript then
      button:HookScript("OnEnter", function(self)
        self.__lidEditorCollapsedHovered = true
        UpdateCollapsedEditorButtonStyle(self)
      end)
      button:HookScript("OnLeave", function(self)
        self.__lidEditorCollapsedHovered = false
        UpdateCollapsedEditorButtonStyle(self)
      end)
      button:HookScript("OnShow", function(self)
        UpdateCollapsedEditorButtonStyle(self)
      end)
    end
    UpdateCollapsedEditorButtonStyle(button)
    return button
  end

  local function AttachTabActiveBorder(button)
    if not button or button.__activeBorder or type(CreatePurpleOutline) ~= "function" then
      return
    end
    button.__activeBorder = CreatePurpleOutline(button)
  end

  ApplyFrameSkin(editor)
  ApplyEditorState(editor)
  ApplyEditorScale(editor)

  editor:SetMovable(true)
  editor:EnableMouse(true)
  editor:RegisterForDrag("LeftButton")
  editor:SetScript("OnDragStart", function(self) self:StartMoving() end)
  editor:SetScript("OnDragStop", function(self)
    self:StopMovingOrSizing()
    if self.__collapsed then
      local ui = RootDB().ui
      ui.editor = ui.editor or {}
      local point, _, relPoint, x, y = self:GetPoint(1)
      ui.editor.point, ui.editor.relPoint, ui.editor.x, ui.editor.y = point, relPoint, x, y
      return
    end
    SaveEditorState(self)
  end)

  editor:SetResizable(true)
  if editor.SetMinResize then editor:SetMinResize(520, 340) end

  local resizeGrip = CreateFrame("Button", nil, editor)
  resizeGrip:SetSize(16, 16)
  resizeGrip:SetPoint("BOTTOMRIGHT", -2, 2)

  local resizeTexture = resizeGrip:CreateTexture(nil, "ARTWORK")
  resizeTexture:SetAllPoints(true)
  resizeTexture:SetTexture("Interface/ChatFrame/UI-ChatIM-SizeGrabber-Up")

  resizeGrip:RegisterForDrag("LeftButton")
  resizeGrip:SetScript("OnDragStart", function()
    editor.__resizing = true
    editor.__resizeStartW = editor:GetWidth()
    editor.__resizeStartH = editor:GetHeight()
    local left, top = editor:GetLeft(), editor:GetTop()
    if left and top then
      editor:ClearAllPoints()
      editor:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", left, top)
    end

    local cursorX, cursorY = GetCursorPosition()
    local scale = (UIParent and UIParent.GetScale and UIParent:GetScale()) or 1
    editor.__resizeStartX = cursorX / scale
    editor.__resizeStartY = cursorY / scale

    resizeGrip:SetScript("OnUpdate", function()
      local ok, err = pcall(function()
        if not editor.__resizing then return end

        local currentX, currentY = GetCursorPosition()
        local uiScale = (UIParent and UIParent.GetScale and UIParent:GetScale()) or 1
        currentX, currentY = currentX / uiScale, currentY / uiScale

        local deltaX = currentX - editor.__resizeStartX
        local deltaY = editor.__resizeStartY - currentY
        local nextW = (editor.__resizeStartW or editor:GetWidth()) + deltaX
        local nextH = (editor.__resizeStartH or editor:GetHeight()) + deltaY

        local clampedW, clampedH = ClampEditorSize(nextW, nextH)
        editor:SetSize(clampedW, clampedH)
      end)
      if ok then return end
      resizeGrip:SetScript("OnUpdate", nil)
      editor.__resizing = false
      if not warnedResizeOnUpdateFailed then
        warnedResizeOnUpdateFailed = true
        LogShellFailure("Editor resize OnUpdate failed: " .. tostring(err))
      end
    end)
  end)

  resizeGrip:SetScript("OnDragStop", function()
    resizeGrip:SetScript("OnUpdate", nil)
    if editor.__resizeStartX and editor.__resizeStartY then
      local cursorX, cursorY = GetCursorPosition()
      local scale = (UIParent and UIParent.GetScale and UIParent:GetScale()) or 1
      local deltaX = math.abs(((cursorX or 0) / scale) - editor.__resizeStartX)
      local deltaY = math.abs(((cursorY or 0) / scale) - editor.__resizeStartY)
      if deltaX < 2 and deltaY < 2 then
        editor:SetSize(editor.__resizeStartW or editor:GetWidth(), editor.__resizeStartH or editor:GetHeight())
      end
    end

    editor.__resizing = false
    editor.__resizeStartX = nil
    editor.__resizeStartY = nil
    SaveEditorState(editor)
    if editor.UpdateScrollLayout then editor:UpdateScrollLayout() end
  end)

  editor:SetScript("OnSizeChanged", function(self, width, height)
    local ok, err = pcall(function()
      if self.__collapsed then return end
      if self.__sizingClamp or self.__resizing then return end

      local now = GetTime and GetTime() or 0
      if self.__lastSizeTick and (now - self.__lastSizeTick) < 0.05 then return end
      self.__lastSizeTick = now

      local nextW = width or self:GetWidth()
      local nextH = height or self:GetHeight()
      local clampedW, clampedH = ClampEditorSize(nextW, nextH)
      if clampedW ~= nextW or clampedH ~= nextH then
        self.__sizingClamp = true
        self:SetSize(clampedW, clampedH)
        self.__sizingClamp = false
      end

      SaveEditorState(self)
      if self.UpdateScrollLayout then
        self:UpdateScrollLayout()
      end
    end)
    if ok then return end
    self.__sizingClamp = false
    if not warnedEditorSizeChangedFailed then
      warnedEditorSizeChangedFailed = true
      LogShellFailure("Editor OnSizeChanged failed: " .. tostring(err))
    end
  end)

  local logo = editor:CreateTexture(nil, "ARTWORK")
  logo:SetSize(LOGO_TARGET_W, LOGO_TARGET_H)
  logo:SetPoint("TOPLEFT", 12, -10)
  logo:SetTexture("Interface\\AddOns\\LidCouncil\\Media\\LidCouncil\\Logos\\LidCouncil_HeaderLogo.tga")
  editor.logo = logo
  ApplyEditorLogo()

  local title = editor:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
  title:SetPoint("TOPLEFT", logo, "TOPRIGHT", 12, -4)
  title:SetText("LidCouncil Version " .. ADDON_VERSION)
  editor.title = title

  local versionText = editor:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  versionText:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -2)
  versionText:SetText("v" .. WOW_CLIENT_VERSION)
  editor.versionText = versionText

  local close = CreateFrame("Button", nil, editor, "UIPanelCloseButton")
  close:SetPoint("TOPRIGHT", -2, -2)
  close:SetScript("OnClick", function() editor:Hide() end)

  local collapseBtn = CreateFrame("Button", nil, editor, "UIPanelButtonTemplate")
  collapseBtn:SetSize(82, 22)
  collapseBtn:SetPoint("RIGHT", close, "LEFT", -4, 0)
  collapseBtn:SetText("Collapse")
  editor.collapseBtn = collapseBtn

  local collapsedExpandBtn = CreateFrame("Button", nil, editor, "UIPanelButtonTemplate")
  collapsedExpandBtn:SetSize(74, 22)
  collapsedExpandBtn:SetText("Expand")
  collapsedExpandBtn:Hide()
  ApplyCollapsedEditorButtonStyle(collapsedExpandBtn)
  editor.collapsedExpandBtn = collapsedExpandBtn

  local collapsedCloseBtn = CreateFrame("Button", nil, editor, "UIPanelButtonTemplate")
  collapsedCloseBtn:SetSize(70, 22)
  collapsedCloseBtn:SetText("Close")
  collapsedCloseBtn:SetScript("OnClick", function() editor:Hide() end)
  collapsedCloseBtn:Hide()
  ApplyCollapsedEditorButtonStyle(collapsedCloseBtn)
  editor.collapsedCloseBtn = collapsedCloseBtn

  editor:SetScript("OnShow", function()
    if SetAllUnlocked then
      SetAllUnlocked(GetPanelsUnlockedState())
    end
    ApplyEditorScale(editor)
    if editor.ApplyTheme then editor:ApplyTheme() end
  end)

  editor:SetScript("OnHide", function()
    if SetAllUnlocked then
      SetAllUnlocked(GetPanelsUnlockedState())
    end
  end)

  editor:EnableKeyboard(true)
  if editor.SetPropagateKeyboardInput then
    editor:SetPropagateKeyboardInput(true)
  end
  editor:SetScript("OnKeyDown", function(self, key)
    if not self:IsShown() then return end
    if self.currentPage ~= "Panels" or not self.allowKeyboardNudging then
      if self.SetPropagateKeyboardInput then self:SetPropagateKeyboardInput(true) end
      return
    end

    local focus = GetCurrentKeyBoardFocus and GetCurrentKeyBoardFocus()
    if focus and focus.IsDescendantOf and focus:IsDescendantOf(self) then
      if self.SetPropagateKeyboardInput then self:SetPropagateKeyboardInput(true) end
      return
    end

    local step = 1
    if IsShiftKeyDown and IsShiftKeyDown() then step = 10 end

    local deltaX, deltaY = 0, 0
    if key == "LEFT" then
      deltaX = -step
    elseif key == "RIGHT" then
      deltaX = step
    elseif key == "UP" then
      deltaY = step
    elseif key == "DOWN" then
      deltaY = -step
    else
      if self.SetPropagateKeyboardInput then self:SetPropagateKeyboardInput(true) end
      return
    end

    local moved = false
    if NudgeSelectedPanel then
      moved = NudgeSelectedPanel(deltaX, deltaY)
    end
    if self.SetPropagateKeyboardInput then
      self:SetPropagateKeyboardInput(not moved)
    end
  end)

  local headerHeight = math.max(LOGO_TARGET_H + 20, 80)
  editor.headerHeight = headerHeight

  local profileBarHeight = 22
  editor.profileBarHeight = profileBarHeight

  local headerBg = editor:CreateTexture(nil, "BACKGROUND")
  headerBg:SetPoint("TOPLEFT", editor, "TOPLEFT", 2, -2)
  headerBg:SetPoint("TOPRIGHT", editor, "TOPRIGHT", -2, -2)
  headerBg:SetHeight(headerHeight + profileBarHeight + 6)
  if headerBg.SetDrawLayer then headerBg:SetDrawLayer("ARTWORK", -5) end
  headerBg:Hide()
  editor.headerBg = headerBg

  local profileBar = CreateFrame("Frame", nil, editor, "BackdropTemplate")
  profileBar:SetPoint("TOPLEFT", 12, -headerHeight)
  profileBar:SetPoint("TOPRIGHT", -12, -headerHeight)
  profileBar:SetHeight(profileBarHeight)
  profileBar:SetBackdrop({
    bgFile = "Interface/Buttons/WHITE8x8",
    edgeFile = "Interface/Buttons/WHITE8x8",
    tile = false, edgeSize = 1,
    insets = { left = 1, right = 1, top = 1, bottom = 1 }
  })
  profileBar:SetBackdropColor(0.06, 0.06, 0.08, 0.80)
  profileBar:SetBackdropBorderColor(0, 0, 0, 0.7)
  editor.profileBar = profileBar

  local profileBarText = profileBar:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  profileBarText:SetPoint("LEFT", 8, 0)
  profileBarText:SetText("Current Profile: " .. DisplayProfileName("Default"))
  editor.profileBarText = profileBarText

  local tabsOffset = headerHeight + profileBarHeight + 6
  local tabs = CreateFrame("Frame", nil, editor)
  tabs:SetPoint("TOPLEFT", 12, -tabsOffset)
  tabs:SetPoint("TOPRIGHT", -12, -tabsOffset)
  tabs:SetHeight(26)

  local tabDefs = {
    { key = "Profiles", field = "profilesTab", text = "Profile", width = 100 },
    { key = "Panels", field = "panelsTab", text = "Session", width = 100 },
    { key = "LiveBoard", field = "liveBoardTab", text = "Live Board", width = 110 },
    { key = "Backgrounds", field = "backgroundsTab", text = "Loot List", width = 120 },
    { key = "UI", field = "uiTab", text = "UI Settings", width = 120 },
    { key = "Tutorial", field = "tutorialTab", text = "Tutorial", width = 100 },
    { key = "About", field = "aboutTab", text = "About", width = 100 },
  }

  editor.mainTabs = {}
  local previousTab
  for _, def in ipairs(tabDefs) do
    local button = CreateMainTab(tabs, previousTab, def)
    editor[def.field] = button
    editor.mainTabs[def.key] = button
    AttachTabActiveBorder(button)
    previousTab = button
  end

  function editor:UpdateMainTabHighlight()
    local activePage = self.currentPage or "Profiles"
    local palette = GetEditorThemePalette and GetEditorThemePalette() or nil
    local useLootPilot = type(palette) == "table" and (palette.key == "lootpilot" or palette.key == "white_orange")
    local activeColor = useLootPilot and (palette.text or { 1, 1, 1, 1 }) or type(palette) == "table" and type(palette.aboutTitle) == "table"
      and palette.aboutTitle
      or { 0.6588, 0.4784, 0.9098, 1.0 }
    local borderColor = type(palette) == "table" and type(palette.selectionAccent) == "table"
      and palette.selectionAccent
      or activeColor
    local activeR = activeColor[1] or 0.6588
    local activeG = activeColor[2] or 0.4784
    local activeB = activeColor[3] or 0.9098
    for page, button in pairs(self.mainTabs or {}) do
      local isActive = (page == activePage)
      if button.__activeBorder then
        button.__activeBorder:SetShown(isActive)
        if button.__activeBorder.SetBackdropBorderColor then
          button.__activeBorder:SetBackdropBorderColor(
            borderColor[1] or activeR,
            borderColor[2] or activeG,
            borderColor[3] or activeB,
            borderColor[4] or 0.95
          )
        end
      end

      local fontString = button.GetFontString and button:GetFontString()
      if fontString then
        if useLootPilot then
          fontString:SetTextColor(1, 1, 1, 1)
        elseif isActive then
          fontString:SetTextColor(activeR, activeG, activeB, 1)
        else
          fontString:SetTextColor(1, 1, 1, 1)
        end
      end
    end
  end

  local scrollFrame = CreateFrame("ScrollFrame", nil, editor, "UIPanelScrollFrameTemplate")
  scrollFrame:SetPoint("TOPLEFT", 12, -(tabsOffset + 30))
  scrollFrame:SetPoint("BOTTOMRIGHT", -12, 12)
  scrollFrame:EnableMouseWheel(false)
  scrollFrame:SetScript("OnMouseWheel", function(self, delta)
    local scrollBar = self.ScrollBar
    if not scrollBar then return end
    local current = scrollBar:GetValue()
    local minValue, maxValue = scrollBar:GetMinMaxValues()
    local nextValue = current - (delta * 20)
    if nextValue < minValue then nextValue = minValue end
    if nextValue > maxValue then nextValue = maxValue end
    scrollBar:SetValue(nextValue)
  end)

  local scrollChild = CreateFrame("Frame", nil, scrollFrame)
  scrollChild:SetSize(1, 1)
  scrollFrame:SetScrollChild(scrollChild)

  editor.scrollFrame = scrollFrame
  editor.scrollChild = scrollChild

  local panelsPage, panelsTitle, panelsCurrentLabel = CreateRootPage(scrollChild, "Session")
  local liveBoardPage, liveBoardTitle, liveBoardCurrentLabel = CreateRootPage(scrollChild, "Live Board")
  local backgroundsPage, backgroundsTitle, backgroundsCurrentLabel = CreateRootPage(scrollChild, "Loot List")
  local profilesPage, profilesTitle, profilesCurrentLabel = CreateRootPage(scrollChild, "Profile")
  local uiPage, uiPageTitle, uiCurrentLabel = CreateRootPage(scrollChild, "UI Settings")
  local tutorialPage, tutorialPageTitle, tutorialCurrentLabel = CreateRootPage(scrollChild, "Tutorial")
  local aboutPage, aboutPageTitle, aboutCurrentLabel = CreateRootPage(scrollChild, "About")

  liveBoardPage:Hide()
  backgroundsPage:Hide()
  profilesPage:Hide()
  uiPage:Hide()
  tutorialPage:Hide()
  aboutPage:Hide()

  editor.panelsPage = panelsPage
  editor.liveBoardPage = liveBoardPage
  editor.profilesPage = profilesPage
  editor.backgroundsPage = backgroundsPage
  editor.uiPage = uiPage
  editor.tutorialPage = tutorialPage
  editor.aboutPage = aboutPage

  editor.profilesTitle = profilesTitle
  editor.profilesCurrentLabel = profilesCurrentLabel
  editor.panelsTitle = panelsTitle
  editor.panelsCurrentLabel = panelsCurrentLabel
  editor.liveBoardTitle = liveBoardTitle
  editor.liveBoardCurrentLabel = liveBoardCurrentLabel
  editor.backgroundsTitle = backgroundsTitle
  editor.backgroundsCurrentLabel = backgroundsCurrentLabel
  editor.uiPageTitle = uiPageTitle
  editor.uiCurrentLabel = uiCurrentLabel
  editor.tutorialPageTitle = tutorialPageTitle
  editor.tutorialCurrentLabel = tutorialCurrentLabel
  editor.aboutPageTitle = aboutPageTitle
  editor.aboutCurrentLabel = aboutCurrentLabel

  local pages = {
    Panels = panelsPage,
    LiveBoard = liveBoardPage,
    Profiles = profilesPage,
    Backgrounds = backgroundsPage,
    UI = uiPage,
    Tutorial = tutorialPage,
    About = aboutPage,
  }
  editor.pages = pages

  local function UpdateScrollChildSize(height)
    if type(height) ~= "number" then height = 800 end
    local width = (scrollFrame.GetWidth and scrollFrame:GetWidth()) or 1
    width = math.max(1, math.floor(width))
    local finalHeight = math.max(1, height)
    scrollChild:SetSize(width, finalHeight)
    if scrollFrame.UpdateScrollChildRect then scrollFrame:UpdateScrollChildRect() end
  end
  editor.UpdateScrollChildSize = UpdateScrollChildSize

  local function UpdateScrollLayout()
    if editor.__collapsed then return end
    if editor.__updatingScrollLayout then return end
    editor.__updatingScrollLayout = true

    local currentPage = editor.currentPage or "Panels"
    local viewHeight = (scrollFrame.GetHeight and scrollFrame:GetHeight()) or 800
    local useViewportHeight = (
      currentPage == "Panels"
      or currentPage == "UI"
      or currentPage == "Tutorial"
      or currentPage == "About"
    )
    UpdateScrollChildSize(viewHeight)

    if currentPage == "Profiles" and editor.LayoutLootProfilePage then
      editor:LayoutLootProfilePage()
    elseif currentPage == "Panels" and editor.LayoutLootSessionPage then
      editor:LayoutLootSessionPage()
    elseif currentPage == "LiveBoard" and editor.LayoutLootLiveBoardPage then
      editor:LayoutLootLiveBoardPage()
    elseif currentPage == "Backgrounds" and editor.RefreshLootListPage then
      editor:RefreshLootListPage()
    end

    if currentPage == "Tutorial" and editor.ShowTutorialSection then
      editor:ShowTutorialSection(editor.tutorialSection or "Beginner")
    end

    local currentFrame = pages[currentPage]
    local contentHeight = (currentFrame and currentFrame.__contentHeight) or viewHeight

    local targetHeight = useViewportHeight and viewHeight or math.max(contentHeight, viewHeight)
    editor.currentPageHeight = targetHeight
    if targetHeight ~= viewHeight then
      UpdateScrollChildSize(targetHeight)
    end
    local useOuterScroll = currentPage == "LiveBoard"
    local showOuterScroll = useOuterScroll and targetHeight > (viewHeight + 1)
    scrollFrame:EnableMouseWheel(useOuterScroll)
    if scrollFrame.ScrollBar then
      scrollFrame.ScrollBar:SetShown(showOuterScroll)
      if not showOuterScroll and scrollFrame.ScrollBar.SetValue then
        scrollFrame.ScrollBar:SetValue(0)
      end
    end

    editor.__updatingScrollLayout = false
  end
  editor.UpdateScrollLayout = UpdateScrollLayout

  local function SetEditorCollapsed(collapsed)
    local nextCollapsed = collapsed == true
    if editor.__collapsed == nextCollapsed then
      return
    end

    AnchorEditorToCurrentTopLeft()

    editor.__collapsed = nextCollapsed
    local root = type(RootDB) == "function" and RootDB() or nil
    local ui = type(root) == "table" and type(root.ui) == "table" and root.ui or nil
    if ui then
      ui.editor = type(ui.editor) == "table" and ui.editor or {}
      ui.editor.collapsed = nextCollapsed
    end

    if nextCollapsed then
      editor.__expandedW = editor:GetWidth()
      editor.__expandedH = editor:GetHeight()
      SetEditorBackdropVisible(true)
      if headerBg then headerBg:Hide() end
      if logo then logo:Hide() end
      if title then
        title:Show()
        title:ClearAllPoints()
        title:SetPoint("TOPLEFT", 16, -14)
        title:SetText("LidCouncil")
      end
      if versionText then
        versionText:Show()
        versionText:ClearAllPoints()
        versionText:SetPoint("TOPLEFT", 16, -38)
        versionText:SetWidth(344)
        versionText:SetText("Editor collapsed")
      end
      profileBar:Hide()
      tabs:Hide()
      scrollFrame:Hide()
      if resizeGrip then resizeGrip:Hide() end
      if editor.SetResizable then editor:SetResizable(false) end
      if editor.SetMinResize then editor:SetMinResize(380, 84) end
      editor:SetSize(380, 84)
      if close then close:Hide() end
      if collapseBtn then collapseBtn:Hide() end
      if collapsedCloseBtn then
        collapsedCloseBtn:ClearAllPoints()
        collapsedCloseBtn:SetPoint("TOPRIGHT", -16, -12)
        collapsedCloseBtn:Show()
        UpdateCollapsedEditorButtonStyle(collapsedCloseBtn)
      end
      if collapsedExpandBtn then
        local titleWidth = math.max(100, math.ceil((title and title.GetStringWidth and title:GetStringWidth()) or 100))
        collapsedExpandBtn:ClearAllPoints()
        collapsedExpandBtn:SetPoint("TOPLEFT", 16 + titleWidth + 12, -12)
        collapsedExpandBtn:Show()
        UpdateCollapsedEditorButtonStyle(collapsedExpandBtn)
      end
      AnchorEditorToCurrentTopLeft()
      return
    end

    SetEditorBackdropVisible(true)
    if logo then logo:Show() end
    if title then
      title:Show()
      title:ClearAllPoints()
      title:SetPoint("TOPLEFT", logo, "TOPRIGHT", 12, -4)
      title:SetText("LidCouncil Version " .. ADDON_VERSION)
    end
    if versionText then
      versionText:Show()
      versionText:ClearAllPoints()
      versionText:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -2)
      versionText:SetWidth(360)
      versionText:SetText("v" .. WOW_CLIENT_VERSION)
    end
    if collapsedExpandBtn then collapsedExpandBtn:Hide() end
    if collapsedCloseBtn then collapsedCloseBtn:Hide() end
    profileBar:Show()
    tabs:Show()
    scrollFrame:Show()
    if resizeGrip then resizeGrip:Show() end
    if editor.SetResizable then editor:SetResizable(true) end
    if editor.SetMinResize then editor:SetMinResize(520, 340) end
    if close then
      close:SetSize(32, 32)
      close:ClearAllPoints()
      close:SetPoint("TOPRIGHT", -2, -2)
      close:Show()
    end
    if collapseBtn then
      collapseBtn:SetSize(82, 22)
      collapseBtn:ClearAllPoints()
      collapseBtn:SetPoint("RIGHT", close, "LEFT", -4, 0)
      collapseBtn:Show()
    end
    local restoreW = tonumber(editor.__expandedW)
    local restoreH = tonumber(editor.__expandedH)
    if restoreW and restoreH then
      local clampedW, clampedH = ClampEditorSize(restoreW, restoreH)
      editor:SetSize(clampedW, clampedH)
    end
    if collapseBtn then collapseBtn:SetText("Collapse") end
    AnchorEditorToCurrentTopLeft()
    SaveEditorState(editor)
    UpdateScrollLayout()
  end
  editor.SetEditorCollapsed = SetEditorCollapsed

  if collapseBtn then
    collapseBtn:SetScript("OnClick", function()
      SetEditorCollapsed(not editor.__collapsed)
    end)
  end
  if collapsedExpandBtn then
    collapsedExpandBtn:SetScript("OnClick", function()
      SetEditorCollapsed(false)
    end)
  end

  do
    local root = type(RootDB) == "function" and RootDB() or nil
    local ui = type(root) == "table" and type(root.ui) == "table" and root.ui or nil
    local st = type(ui) == "table" and type(ui.editor) == "table" and ui.editor or nil
    if type(st) == "table" and st.collapsed == true then
      editor.__collapsed = false
      SetEditorCollapsed(true)
    end
  end

  if type(BuildTutorialPage) == "function" then
    BuildTutorialPage(editor, tutorialPage)
  end

  local function ShowPage(which)
    for pageName, page in pairs(pages) do
      page:SetShown(pageName == which)
    end

    editor.currentPage = which
    if which == "LiveBoard" and type(RootDB) == "function" then
      local root = RootDB()
      root.ui = root.ui or {}
      root.ui.lootLiveBoardMode = "EMBEDDED"
      root.ui.lootLiveBoardView = "BOARD"
    end
    if which == "About" and editor.ShowAboutSection then
      editor:ShowAboutSection("Overview")
    end
    if which == "Tutorial" and editor.ShowTutorialSection then
      editor:ShowTutorialSection(editor.tutorialSection or "Beginner")
    end
    if editor.UpdateScrollLayout then editor:UpdateScrollLayout() end
    scrollFrame:SetVerticalScroll(0)

    if editor.ApplyTheme then editor:ApplyTheme() end
    if editor.UpdateMainTabHighlight then editor:UpdateMainTabHighlight() end
  end

  editor.ShowPage = ShowPage
  editor.profilesTab:SetScript("OnClick", function() ShowPage("Profiles") end)
  editor.panelsTab:SetScript("OnClick", function() ShowPage("Panels") end)
  editor.liveBoardTab:SetScript("OnClick", function() ShowPage("LiveBoard") end)
  editor.backgroundsTab:SetScript("OnClick", function() ShowPage("Backgrounds") end)
  editor.uiTab:SetScript("OnClick", function() ShowPage("UI") end)
  editor.tutorialTab:SetScript("OnClick", function() ShowPage("Tutorial") end)
  editor.aboutTab:SetScript("OnClick", function() ShowPage("About") end)

  return {
    panelsPage = panelsPage,
    liveBoardPage = liveBoardPage,
    profilesPage = profilesPage,
    backgroundsPage = backgroundsPage,
    uiPage = uiPage,
    tutorialPage = tutorialPage,
    aboutPage = aboutPage,
  }
end

INTERNAL_API.LIDCOUNCIL_SetupEditorFrameShell = SetupEditorFrameShell
