-- LidCouncil_Editor_UIHelpers.lua
-- Shared editor UI helpers extracted from Editor.lua.

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 getDeps = INTERNAL_API.LIDCOUNCIL_GetEditorUiHelpersDeps_Impl
if type(getDeps) ~= "function" then
  error("LidCouncil missing editor UI helper dependencies.")
end

local deps = getDeps()
local RootDB = deps.RootDB
local Compat = deps.Compat
local LISTS_PER_PAGE = deps.LISTS_PER_PAGE or 18

local DEFAULT_SKIN_HEADER = "Interface\\AddOns\\LidCouncil\\Media\\LidCouncil\\Logos\\LidCouncil_HeaderBackground.tga"
local WHITE_ORANGE_SKIN_HEADER = "Interface\\AddOns\\LidCouncil\\Media\\LidCouncil\\Logos\\LidCouncil_HeaderBackground2.tga"
local DEFAULT_SKIN_HEADER_SRC_W = 116
local DEFAULT_SKIN_HEADER_SRC_H = 54
local LOGO_TEXTURE_PATH = "Interface\\AddOns\\LidCouncil\\Media\\LidCouncil\\Logos\\LidCouncil_HeaderLogo.tga"
local HEADER_LOGO_TEXTURES = {
  headerlogo = "Interface\\AddOns\\LidCouncil\\Media\\LidCouncil\\Logos\\LidCouncil_HeaderLogo.tga",
  headerlogo2 = "Interface\\AddOns\\LidCouncil\\Media\\LidCouncil\\Logos\\LidCouncil_HeaderLogo2.tga",
  headerlogo3 = "Interface\\AddOns\\LidCouncil\\Media\\LidCouncil\\Logos\\LidCouncil_HeaderLogo3.tga",
  headerlogo4 = "Interface\\AddOns\\LidCouncil\\Media\\LidCouncil\\Logos\\LidCouncil_HeaderLogo4.tga",
  headerlogo5 = "Interface\\AddOns\\LidCouncil\\Media\\LidCouncil\\Logos\\LidCouncil_HeaderLogo5.tga",
  headerlogo6 = "Interface\\AddOns\\LidCouncil\\Media\\LidCouncil\\Logos\\LidCouncil_HeaderLogo6.tga",
  headerlogo7 = "Interface\\AddOns\\LidCouncil\\Media\\LidCouncil\\Logos\\LidCouncil_HeaderLogo7.tga",
  headerlogo8 = "Interface\\AddOns\\LidCouncil\\Media\\LidCouncil\\Logos\\LidCouncil_HeaderLogo8.tga",
  headerlogo9 = "Interface\\AddOns\\LidCouncil\\Media\\LidCouncil\\Logos\\LidCouncil_HeaderLogo9.tga",
}

local DEFAULT_EDITOR_SKIN_KEY = "lidcouncil"
local EDITOR_SKIN_PRESETS = {
  lidcouncil = {
    key = "lidcouncil",
    logoKey = "HeaderLogo",
    logo = LOGO_TEXTURE_PATH,
    header = DEFAULT_SKIN_HEADER,
  },
  lootpilot = {
    key = "lootpilot",
    logoKey = "NONE",
    logo = nil,
    header = WHITE_ORANGE_SKIN_HEADER,
  },
}
EDITOR_SKIN_PRESETS.white_orange = EDITOR_SKIN_PRESETS.lootpilot

local TALENT_TEXCOORD = {
  FULL = { 0.0, 0.77, 0.0, 0.75 },
  TOP = { 0.0, 0.77, 0.0, 0.38 },
  BOTTOM = { 0.0, 0.77, 0.38, 0.75 },
}

local TALENT_BACKGROUND_DEFS = {
  { text = "Death Knight - Blood", fileID = 4631290, split = "TOP" },
  { text = "Death Knight - Frost", fileID = 4631290, split = "BOTTOM" },
  { text = "Death Knight - Unholy", fileID = 4631293, split = "FULL" },
  { text = "Demon Hunter - Havoc", fileID = 4631296, split = "TOP" },
  { text = "Demon Hunter - Vengeance", fileID = 4631296, split = "BOTTOM" },
  { text = "Demon Hunter - Devourer", fileID = 7323575, split = "FULL" },
  { text = "Druid - Balance", fileID = 4631299, split = "TOP" },
  { text = "Druid - Feral", fileID = 4631299, split = "BOTTOM" },
  { text = "Druid - Guardian", fileID = 4631304, split = "TOP" },
  { text = "Druid - Restoration", fileID = 4631304, split = "BOTTOM" },
  { text = "Evoker - Devastation", fileID = 4631307, split = "TOP" },
  { text = "Evoker - Preservation", fileID = 4631307, split = "BOTTOM" },
  { text = "Evoker - Augmentation", fileID = 5179179, split = "FULL" },
  { text = "Hunter - Beast Mastery", fileID = 4631310, split = "TOP" },
  { text = "Hunter - Marksmanship", fileID = 4631310, split = "BOTTOM" },
  { text = "Hunter - Survival", fileID = 4631313, split = "FULL" },
  { text = "Mage - Arcane", fileID = 4631318, split = "TOP" },
  { text = "Mage - Fire", fileID = 4631318, split = "BOTTOM" },
  { text = "Mage - Frost", fileID = 4631321, split = "FULL" },
  { text = "Monk - Brewmaster", fileID = 4631324, split = "TOP" },
  { text = "Monk - Mistweaver", fileID = 4631324, split = "BOTTOM" },
  { text = "Monk - Windwalker", fileID = 4631329, split = "FULL" },
  { text = "Paladin - Holy", fileID = 4631337, split = "TOP" },
  { text = "Paladin - Protection", fileID = 4631337, split = "BOTTOM" },
  { text = "Paladin - Retribution", fileID = 4631340, split = "FULL" },
  { text = "Priest - Discipline", fileID = 4631348, split = "TOP" },
  { text = "Priest - Holy", fileID = 4631348, split = "BOTTOM" },
  { text = "Priest - Shadow", fileID = 4631371, split = "FULL" },
  { text = "Rogue - Assassination", fileID = 4631374, split = "TOP" },
  { text = "Rogue - Outlaw", fileID = 4631374, split = "BOTTOM" },
  { text = "Rogue - Subtlety", fileID = 4631377, split = "FULL" },
  { text = "Shaman - Elemental", fileID = 4631381, split = "TOP" },
  { text = "Shaman - Enhancement", fileID = 4631381, split = "BOTTOM" },
  { text = "Shaman - Restoration", fileID = 4631383, split = "FULL" },
  { text = "Warlock - Affliction", fileID = 4631386, split = "TOP" },
  { text = "Warlock - Demonology", fileID = 4631386, split = "BOTTOM" },
  { text = "Warlock - Destruction", fileID = 4631389, split = "FULL" },
  { text = "Warrior - Arms", fileID = 4631392, split = "TOP" },
  { text = "Warrior - Fury", fileID = 4631392, split = "BOTTOM" },
  { text = "Warrior - Protection", fileID = 4631395, split = "FULL" },
}

local function GetEditor()
  return deps.GetEditor()
end

local function ResolveTextureDimensions(path)
  if type(path) ~= "string" or path == "" then
    return nil, nil
  end
  if C_Texture and C_Texture.GetFileIDFromPath and C_Texture.GetTextureInfo then
    local fileID = C_Texture.GetFileIDFromPath(path)
    if fileID then
      local width, height = C_Texture.GetTextureInfo(fileID)
      if type(width) == "table" then
        local info = width
        width = info.width
        height = info.height
      end
      width = tonumber(width)
      height = tonumber(height)
      if width and width > 0 and height and height > 0 then
        return width, height
      end
    end
  end
  return nil, nil
end

local function ApplySkinPreset()
  local ui = RootDB().ui
  ui.skin = "LP"
  local editorSkin = type(ui.editorSkin) == "string" and string.lower(ui.editorSkin) or DEFAULT_EDITOR_SKIN_KEY
  if not EDITOR_SKIN_PRESETS[editorSkin] then
    editorSkin = DEFAULT_EDITOR_SKIN_KEY
  end
  ui.editorSkin = editorSkin
  ui.headerBg = nil
  ui.__skinPreset = "LP"
end

local function ApplyFrameSkin(frame)
  frame:SetBackdrop({
    bgFile = "Interface/Tooltips/UI-Tooltip-Background",
    edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
    tile = true, tileSize = 16, edgeSize = 12,
    insets = { left = 3, right = 3, top = 3, bottom = 3 }
  })
  frame:SetBackdropColor(0.03, 0.03, 0.04, 0.94)
end

local function ResolveEditorHeaderLogoPath()
  local ui = RootDB().ui
  local editorSkin = type(ui.editorSkin) == "string" and string.lower(ui.editorSkin) or DEFAULT_EDITOR_SKIN_KEY
  local preset = EDITOR_SKIN_PRESETS[editorSkin] or EDITOR_SKIN_PRESETS[DEFAULT_EDITOR_SKIN_KEY]
  ui.editorSkin = preset.key
  ui.headerLogo = preset.logoKey or "HeaderLogo"
  return preset.logo
end

local function ApplyEditorLogo()
  local editor = GetEditor()
  if not editor or not editor.logo then
    return
  end
  local logoPath = ResolveEditorHeaderLogoPath()
  if type(logoPath) == "string" and logoPath ~= "" then
    editor.logo:SetTexture(logoPath)
    editor.logo:Show()
  else
    editor.logo:SetTexture(nil)
    editor.logo:Hide()
  end
  if editor.__collapsed == true then
    editor.logo:Hide()
    if editor.activeSessionLogo then
      editor.activeSessionLogo:Hide()
    end
    return
  end
  if editor.activeSessionLogo then
    if type(logoPath) == "string"
      and logoPath ~= ""
      and editor.__lidSessionParticipating == true
      and editor.__collapsed ~= true
    then
      editor.activeSessionLogo:Show()
    else
      editor.activeSessionLogo:Hide()
    end
  end
  if editor.sessionInfoCard then
    if type(editor.UpdateSessionInfoCardLayout) == "function" then
      editor:UpdateSessionInfoCardLayout()
    end
  end
  if editor.title then
    editor.title:ClearAllPoints()
    if editor.sessionInfoCard then
      editor.title:SetPoint("TOPLEFT", editor.sessionInfoCard, "TOPLEFT", 10, -6)
      editor.title:SetPoint("TOPRIGHT", editor.sessionInfoCard, "TOPRIGHT", -56, -6)
    elseif type(logoPath) == "string" and logoPath ~= "" then
      editor.title:SetPoint("TOPLEFT", editor.logo, "TOPRIGHT", 12, -4)
    else
      editor.title:SetPoint("TOPLEFT", editor, "TOPLEFT", 18, -14)
    end
  end
  if editor.versionText and editor.title then
    editor.versionText:ClearAllPoints()
    editor.versionText:SetPoint("TOPLEFT", editor.title, "BOTTOMLEFT", 0, -1)
  end
end

local function ApplyHeaderBackground()
  local editor = GetEditor()
  if not editor or not editor.headerBg then
    return
  end
  local tex = editor.headerBg
  if editor.__collapsed then
    tex:Hide()
    return
  end
  local fallbackH = (tonumber(editor.headerHeight) or 0) + (tonumber(editor.profileBarHeight) or 0) + 6
  local resolvedH = math.max(fallbackH, 1)
  if tex.SetAtlas then
    tex:SetAtlas(nil)
  end
  tex:SetTexture(nil)
  if tex.SetDesaturated then
    tex:SetDesaturated(false)
  end
  local ui = RootDB().ui
  local editorSkin = type(ui.editorSkin) == "string" and string.lower(ui.editorSkin) or DEFAULT_EDITOR_SKIN_KEY
  local preset = EDITOR_SKIN_PRESETS[editorSkin] or EDITOR_SKIN_PRESETS[DEFAULT_EDITOR_SKIN_KEY]
  ui.editorSkin = preset.key
  tex:SetVertexColor(1, 1, 1, 1)
  tex:SetAlpha(1)
  tex:SetBlendMode("BLEND")
  tex:SetTexture(preset.header or DEFAULT_SKIN_HEADER)
  tex:SetTexCoord(0, 1, 0, 1)
  tex:ClearAllPoints()
  tex:SetPoint("TOPLEFT", editor, "TOPLEFT", 2, -2)
  tex:SetPoint("TOPRIGHT", editor, "TOPRIGHT", -2, -2)
  tex:SetHeight(resolvedH)
  tex:Show()
  if Compat and Compat.After then
    Compat.After(0.05, function()
      if editor and editor.headerBg == tex then
        if editor.__collapsed then
          tex:Hide()
          return
        end
        if tex.SetDesaturated then
          tex:SetDesaturated(false)
        end
        tex:SetVertexColor(1, 1, 1, 1)
        tex:SetAlpha(1)
        tex:SetBlendMode("BLEND")
        tex:SetTexCoord(0, 1, 0, 1)
        tex:ClearAllPoints()
        tex:SetPoint("TOPLEFT", editor, "TOPLEFT", 2, -2)
        tex:SetPoint("TOPRIGHT", editor, "TOPRIGHT", -2, -2)
        tex:SetHeight(resolvedH)
      end
    end)
  end
end

local function BuildBackgroundOptions()
  local opts = {}
  for _, def in ipairs(TALENT_BACKGROUND_DEFS) do
    local split = TALENT_TEXCOORD[def.split] or TALENT_TEXCOORD.FULL
    opts[#opts + 1] = {
      text = def.text,
      value = string.format("TALENT:%d:%s", def.fileID, def.split),
      bg = def.fileID,
      texCoord = { split[1], split[2], split[3], split[4] },
    }
  end
  table.sort(opts, function(a, b)
    return a.text < b.text
  end)
  return opts
end

local function BuildBackgroundList(includeNone)
  local list = {}
  if includeNone then
    list[#list + 1] = { text = "Color (no image)", value = "NONE" }
  end
  for _, opt in ipairs(BuildBackgroundOptions()) do
    list[#list + 1] = opt
  end
  return list
end

local function MakeYellowSubHeader(parent, text, x, y)
  local header = parent:CreateFontString(nil, "OVERLAY", "GameFontNormal")
  header:SetPoint("TOPLEFT", x or 0, y or 0)
  header:SetText(text)
  header:SetTextColor(1.0, 0.82, 0.0, 1.0)
  return header
end

local sliderId = 0

local function MakeSlider(parent, label, x, y, minVal, maxVal, step, onValue)
  sliderId = sliderId + 1
  local slider = CreateFrame("Slider", "LIDCOUNCIL_Slider" .. sliderId, parent, "OptionsSliderTemplate")
  slider:SetPoint("TOPLEFT", x, y)
  slider:SetWidth(260)
  slider:SetMinMaxValues(minVal, maxVal)
  slider:SetValueStep(step or 1)
  slider:SetObeyStepOnDrag(true)
  slider:EnableMouse(true)

  local baseName = slider:GetName()
  if baseName then
    _G[baseName .. "Low"]:SetText(tostring(minVal))
    _G[baseName .. "High"]:SetText(tostring(maxVal))
    _G[baseName .. "Text"]:SetText(tostring(label or ""))
  end

  if slider.SetThumbTexture then
    slider:SetThumbTexture("Interface/Buttons/WHITE8x8")
    local thumb = slider.GetThumbTexture and slider:GetThumbTexture()
    if thumb then
      thumb:SetSize(10, 18)
      thumb:SetVertexColor(0.9, 0.9, 0.9, 0.9)
    end
  end

  local editBox = CreateFrame("EditBox", nil, parent, "InputBoxTemplate")
  editBox:SetSize(58, 20)
  editBox:SetPoint("LEFT", slider, "RIGHT", 10, 0)
  editBox:SetAutoFocus(false)
  if minVal >= 0 then
    editBox:SetNumeric(true)
  end
  editBox:SetJustifyH("RIGHT")
  slider.valueBox = editBox

  local function clamp(v)
    if v < minVal then
      return minVal
    end
    if v > maxVal then
      return maxVal
    end
    return v
  end

  local function round(v)
    if v >= 0 then
      return math.floor(v + 0.5)
    end
    return math.ceil(v - 0.5)
  end

  local function setBox(v)
    editBox:SetText(tostring(round(v or 0)))
  end

  slider.SetValueSilent = function(self, v)
    self.__silent = true
    self:SetValue(clamp(v))
    self.__silent = false
  end

  editBox:SetScript("OnEnterPressed", function(self)
    self:ClearFocus()
    local v = tonumber(self:GetText())
    if not v then
      return
    end
    slider:SetValue(clamp(v))
  end)
  editBox:SetScript("OnEscapePressed", function(self)
    self:ClearFocus()
  end)

  slider:SetScript("OnValueChanged", function(self, val)
    setBox(val)
    if self.__silent then
      return
    end
    local editor = GetEditor()
    if editor and editor.__refreshing then
      return
    end
    if onValue then
      onValue(val)
    end
  end)

  setBox(minVal)
  return slider
end

local function AttachListGlow(button)
  if not button then
    return nil
  end
  local glow = button:CreateTexture(nil, "BACKGROUND")
  glow:SetAllPoints(true)
  glow:SetTexture("Interface/Buttons/UI-Listbox-Highlight2")
  glow:SetBlendMode("ADD")
  glow:Hide()
  button.__glow = glow
  return glow
end

local function CreatePurpleOutline(parent)
  if not parent then
    return nil
  end
  local border = CreateFrame("Frame", nil, parent, "BackdropTemplate")
  border:SetPoint("TOPLEFT", -2, 2)
  border:SetPoint("BOTTOMRIGHT", 2, -2)
  border:SetBackdrop({ edgeFile = "Interface/Buttons/WHITE8x8", edgeSize = 1 })
  border:SetBackdropBorderColor(0.6588, 0.4784, 0.9098, 0.95)
  border:Hide()
  return border
end

local function MakeBaseListButton(parent, text, y, onClick)
  local button = CreateFrame("Button", nil, parent, "UIPanelButtonTemplate")
  button:SetSize(200, 20)
  button:SetPoint("TOPLEFT", 0, y)
  button:SetText(text)
  button:SetScript("OnClick", onClick)
  AttachListGlow(button)
  return button
end

local function MakeListButton(parent, text, y, onClick)
  local button = MakeBaseListButton(parent, text, y, onClick)
  local icon = button:CreateTexture(nil, "ARTWORK")
  icon:SetSize(18, 18)
  icon:SetPoint("RIGHT", -6, 0)
  icon:Hide()
  button.__lockIcon = icon
  button.__selectedBorder = CreatePurpleOutline(button)
  return button
end

local function MakeSimpleListButton(parent, text, y, onClick)
  return MakeBaseListButton(parent, text, y, onClick)
end

local function ConfigureProfileGroupButton(button, label, collapsed)
  if not button then
    return
  end

  local fontString = button:GetFontString()
  if fontString then
    fontString:ClearAllPoints()
    fontString:SetPoint("LEFT", 22, 0)
    fontString:SetPoint("RIGHT", -8, 0)
    fontString:SetJustifyH("LEFT")
  end

  if not button.__groupArrowButton then
    local arrowButton = CreateFrame("Button", nil, button)
    arrowButton:SetPoint("TOPLEFT", 2, -1)
    arrowButton:SetPoint("BOTTOMLEFT", 2, 1)
    arrowButton:SetWidth(18)
    arrowButton:RegisterForClicks("LeftButtonUp")
    arrowButton:SetScript("OnClick", function()
      if button.__onToggleProfileGroup then
        button.__onToggleProfileGroup()
      end
    end)
    button.__groupArrowButton = arrowButton

    local arrow = arrowButton:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    arrow:SetPoint("CENTER", 0, 0)
    arrow:SetJustifyH("CENTER")
    button.__groupArrow = arrow
  end

  button.__groupArrow:SetText(collapsed and ">" or "v")
  button:SetText(label or "")
end

local function ConfigureBackgroundCategoryGroupButton(button, label, collapsed)
  if not button then
    return
  end

  local fontString = button:GetFontString()
  if fontString then
    fontString:ClearAllPoints()
    fontString:SetPoint("LEFT", 22, 0)
    fontString:SetPoint("RIGHT", -8, 0)
    fontString:SetJustifyH("LEFT")
  end

  if not button.__bgCategoryGroupArrowButton then
    local arrowButton = CreateFrame("Button", nil, button)
    arrowButton:SetPoint("TOPLEFT", 2, -1)
    arrowButton:SetPoint("BOTTOMLEFT", 2, 1)
    arrowButton:SetWidth(18)
    arrowButton:RegisterForClicks("LeftButtonUp")
    arrowButton:SetScript("OnClick", function()
      if button.__onToggleBackgroundCategoryGroup then
        button.__onToggleBackgroundCategoryGroup()
      end
    end)
    button.__bgCategoryGroupArrowButton = arrowButton

    local arrow = arrowButton:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    arrow:SetPoint("CENTER", 0, 0)
    arrow:SetJustifyH("CENTER")
    button.__bgCategoryGroupArrow = arrow
  end

  button.__bgCategoryGroupArrow:SetText(collapsed and ">" or "v")
  button:SetText(label or "")
end

local function MakeProfileButton(parent, text, y, onClick)
  local button = MakeBaseListButton(parent, text, y, onClick)
  local icon = button:CreateTexture(nil, "ARTWORK")
  icon:SetSize(14, 14)
  icon:SetPoint("RIGHT", -4, 0)
  icon:SetTexture("Interface/Buttons/UI-CheckBox-Check")
  icon:Hide()
  button.__activeIcon = icon
  button.__activeBorder = CreatePurpleOutline(button)
  return button
end

local function ClampListPage(page, totalPages)
  totalPages = math.max(1, tonumber(totalPages) or 1)
  page = tonumber(page) or 1
  if page < 1 then
    page = 1
  end
  if page > totalPages then
    page = totalPages
  end
  return page
end

local function GetListPageForValue(list, value, pageSize, getValue)
  if value == nil then
    return nil
  end
  pageSize = math.max(1, tonumber(pageSize) or LISTS_PER_PAGE)
  getValue = getValue or function(item)
    return item
  end
  for index, item in ipairs(list or {}) do
    if getValue(item) == value then
      return math.floor((index - 1) / pageSize) + 1
    end
  end
  return nil
end

local function UpdatePagerControls(prevBtn, nextBtn, pageText, page, totalPages)
  local show = (tonumber(totalPages) or 1) > 1
  if prevBtn then
    prevBtn:SetShown(show)
    prevBtn:SetEnabled(show and page > 1)
  end
  if nextBtn then
    nextBtn:SetShown(show)
    nextBtn:SetEnabled(show and page < totalPages)
  end
  if pageText then
    pageText:SetShown(show)
    if show then
      pageText:SetText(string.format("Page %d / %d", page, totalPages))
    else
      pageText:SetText("")
    end
  end
end

INTERNAL_API.LIDCOUNCIL_EditorUiHelpers_Impl = {
  ApplySkinPreset = ApplySkinPreset,
  ApplyFrameSkin = ApplyFrameSkin,
  ApplyEditorLogo = ApplyEditorLogo,
  ApplyHeaderBackground = ApplyHeaderBackground,
  BuildBackgroundList = BuildBackgroundList,
  MakeYellowSubHeader = MakeYellowSubHeader,
  MakeSlider = MakeSlider,
  CreatePurpleOutline = CreatePurpleOutline,
  MakeListButton = MakeListButton,
  MakeSimpleListButton = MakeSimpleListButton,
  ConfigureProfileGroupButton = ConfigureProfileGroupButton,
  ConfigureBackgroundCategoryGroupButton = ConfigureBackgroundCategoryGroupButton,
  MakeProfileButton = MakeProfileButton,
  ClampListPage = ClampListPage,
  GetListPageForValue = GetListPageForValue,
  UpdatePagerControls = UpdatePagerControls,
}
