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

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 st = (RootDB().ui and RootDB().ui.editor) or {}
    if st.maxW then maxW = math.min(maxW, st.maxW) end
    if st.maxH then maxH = math.min(maxH, st.maxH) end

    local clampedW = math.min(math.max(width, minW), maxW)
    local clampedH = math.min(math.max(height, minH), maxH)
    return clampedW, clampedH
  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()
    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.__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\\LidPanels\\Media\\Lidpanels\\Logos\\LidPanels_HeaderLogo.tga")
  editor.logo = logo
  ApplyEditorLogo()

  local title = editor:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
  title:SetPoint("TOPLEFT", logo, "TOPRIGHT", 12, -4)
  title:SetText("LidPanels 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)

  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" 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", 2, -2)
  headerBg:SetPoint("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 = "Profiles", width = 100 },
    { key = "Panels", field = "panelsTab", text = "Panels", width = 100 },
    { key = "Backgrounds", field = "backgroundsTab", text = "My Backgrounds", width = 140 },
    { 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"
    for page, button in pairs(self.mainTabs or {}) do
      local isActive = (page == activePage)
      if button.__activeBorder then
        button.__activeBorder:SetShown(isActive)
      end

      local fontString = button.GetFontString and button:GetFontString()
      if fontString then
        if isActive then
          fontString:SetTextColor(0.6588, 0.4784, 0.9098, 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", -30, 12)
  scrollFrame:EnableMouseWheel(true)
  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, "Panels")
  local backgroundsPage, backgroundsTitle, backgroundsCurrentLabel = CreateRootPage(scrollChild, "My Backgrounds")
  local profilesPage = CreateRootPage(scrollChild, nil)
  local uiPage, uiPageTitle, uiCurrentLabel = CreateRootPage(scrollChild, "UI Settings")
  local tutorialPage, tutorialPageTitle, tutorialCurrentLabel = CreateRootPage(scrollChild, "Tutorial")
  local aboutPage, aboutPageTitle, aboutCurrentLabel = CreateRootPage(scrollChild, "About")

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

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

  editor.panelsTitle = panelsTitle
  editor.panelsCurrentLabel = panelsCurrentLabel
  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,
    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 - 28))
    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.__updatingScrollLayout then return end
    editor.__updatingScrollLayout = true

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

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

    local contentHeight = viewHeight
    if currentPage == "UI" then
      contentHeight = uiPage.__contentHeight or viewHeight
    end

    local targetHeight = math.max(contentHeight, viewHeight)
    editor.currentPageHeight = targetHeight
    if targetHeight ~= viewHeight then
      UpdateScrollChildSize(targetHeight)
    end

    if (currentPage == "Tutorial" or currentPage == "About") and scrollFrame.ScrollBar then
      scrollFrame.ScrollBar:SetShown(false)
      scrollFrame:EnableMouseWheel(false)
    end

    editor.__updatingScrollLayout = false
  end
  editor.UpdateScrollLayout = UpdateScrollLayout

  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 == "About" and editor.ShowAboutSection then
      editor:ShowAboutSection("Overview")
    end
    if which == "Tutorial" and editor.ShowTutorialSection then
      editor:ShowTutorialSection(editor.tutorialSection or "Profiles")
    end
    if editor.UpdateScrollLayout then editor:UpdateScrollLayout() end
    scrollFrame:SetVerticalScroll(0)

    local useOuterScroll = (which == "UI")
    scrollFrame:EnableMouseWheel(useOuterScroll)
    if scrollFrame.ScrollBar then
      scrollFrame.ScrollBar:SetShown(useOuterScroll)
    end
    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.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,
    profilesPage = profilesPage,
    backgroundsPage = backgroundsPage,
    uiPage = uiPage,
    tutorialPage = tutorialPage,
    aboutPage = aboutPage,
  }
end

INTERNAL_API.LIDPANELS_SetupEditorFrameShell = SetupEditorFrameShell
