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

INTERNAL_API.LIDCOUNCIL_CreatePanelTexturePickerHelpers_Impl = function(deps)
  deps = type(deps) == "table" and deps or {}

  local editor = deps.editor
  local ApplyFrameSkin = deps.ApplyFrameSkin
  local HideOtherPickers = deps.HideOtherPickers
  local textureEntries = deps.textureEntries or {}

  local function ShowTexturePicker(onSelect)
    HideOtherPickers("texturePicker")
    if not editor.texturePicker then
      local picker = CreateFrame("Frame", "LIDCOUNCIL_TexturePicker", UIParent, "BackdropTemplate")
      picker:SetFrameStrata("DIALOG")
      picker:SetSize(760, 480)
      picker:SetPoint("CENTER")
      picker:SetClampedToScreen(true)
      picker:SetMovable(true)
      picker:EnableMouse(true)
      picker:RegisterForDrag("LeftButton")
      picker:SetScript("OnDragStart", function(self) self:StartMoving() end)
      picker:SetScript("OnDragStop", function(self) self:StopMovingOrSizing() end)
      ApplyFrameSkin(picker)

      local title = picker:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
      title:SetPoint("TOPLEFT", 12, -10)
      title:SetText("Select Texture")

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

      local filterFrame = CreateFrame("Frame", nil, picker, "BackdropTemplate")
      filterFrame:SetPoint("TOPLEFT", 12, -64)
      filterFrame:SetPoint("BOTTOMLEFT", 12, 42)
      filterFrame:SetWidth(110)
      ApplyFrameSkin(filterFrame)
      picker.filterFrame = filterFrame

      local catTitle = filterFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
      catTitle:SetPoint("TOPLEFT", 10, -6)
      catTitle:SetText("Categories")

      local catScroll = CreateFrame("ScrollFrame", nil, filterFrame, "UIPanelScrollFrameTemplate")
      catScroll:SetPoint("TOPLEFT", 6, -24)
      catScroll:SetPoint("BOTTOMRIGHT", -22, 6)
      local catContent = CreateFrame("Frame", nil, catScroll)
      catContent:SetPoint("TOPLEFT", 0, 0)
      catContent:SetSize(1, 1)
      catScroll:SetScrollChild(catContent)

      local subFilterFrame = CreateFrame("Frame", nil, picker, "BackdropTemplate")
      subFilterFrame:SetPoint("TOPLEFT", filterFrame, "TOPRIGHT", 8, 0)
      subFilterFrame:SetPoint("BOTTOMLEFT", filterFrame, "BOTTOMRIGHT", 8, 0)
      subFilterFrame:SetWidth(160)
      ApplyFrameSkin(subFilterFrame)

      local subTitle = subFilterFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
      subTitle:SetPoint("TOPLEFT", 10, -6)
      subTitle:SetText("Preset Filters")

      local subScroll = CreateFrame("ScrollFrame", nil, subFilterFrame, "UIPanelScrollFrameTemplate")
      subScroll:SetPoint("TOPLEFT", 6, -24)
      subScroll:SetPoint("BOTTOMRIGHT", -22, 6)
      local subContent = CreateFrame("Frame", nil, subScroll)
      subContent:SetPoint("TOPLEFT", 0, 0)
      subContent:SetSize(1, 1)
      subScroll:SetScrollChild(subContent)

      local iconFrame = CreateFrame("Frame", nil, picker, "BackdropTemplate")
      iconFrame:SetPoint("TOPLEFT", subFilterFrame, "TOPRIGHT", 8, 0)
      iconFrame:SetPoint("BOTTOMRIGHT", -12, 42)
      ApplyFrameSkin(iconFrame)

      local scroll = CreateFrame("ScrollFrame", nil, iconFrame, "UIPanelScrollFrameTemplate")
      scroll:SetPoint("TOPLEFT", 6, -34)
      scroll:SetPoint("BOTTOMRIGHT", -28, 32)
      scroll:EnableMouseWheel(true)

      local content = CreateFrame("Frame", nil, scroll)
      content:SetPoint("TOPLEFT", 0, 0)
      content:SetSize(1, 1)
      scroll:SetScrollChild(content)

      local searchBox = CreateFrame("EditBox", nil, picker, "InputBoxTemplate")
      searchBox:SetSize(260, 20)
      searchBox:SetPoint("TOPLEFT", iconFrame, "TOPLEFT", 8, -8)
      searchBox:SetAutoFocus(false)
      searchBox:SetText("")

      local searchLabel = picker:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
      searchLabel:SetPoint("RIGHT", searchBox, "LEFT", -6, 0)
      searchLabel:SetText("Search:")

      local prevBtn = CreateFrame("Button", nil, picker, "UIPanelButtonTemplate")
      prevBtn:SetSize(28, 20)
      prevBtn:SetPoint("BOTTOMLEFT", iconFrame, "BOTTOMLEFT", 6, 6)
      prevBtn:SetText("<")

      local nextBtn = CreateFrame("Button", nil, picker, "UIPanelButtonTemplate")
      nextBtn:SetSize(28, 20)
      nextBtn:SetPoint("LEFT", prevBtn, "RIGHT", 6, 0)
      nextBtn:SetText(">")

      local pageLabel = picker:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
      pageLabel:SetPoint("LEFT", nextBtn, "RIGHT", 10, 0)
      pageLabel:SetText("Page 1 / 1")

      local pageEdit = CreateFrame("EditBox", nil, picker, "InputBoxTemplate")
      pageEdit:SetSize(40, 20)
      pageEdit:SetPoint("LEFT", pageLabel, "RIGHT", 8, 0)
      pageEdit:SetAutoFocus(false)
      pageEdit:SetNumeric(true)
      pageEdit:SetText("1")

      local buttons = {}
      local entries = textureEntries

      local catLabels = {}
      local catSeen = {}
      for _, entry in ipairs(entries) do
        local cat = entry.cat or "Other"
        if not catSeen[cat] then
          catSeen[cat] = true
          catLabels[#catLabels + 1] = cat
        end
      end
      table.sort(catLabels, function(a, b)
        return string.lower(a) < string.lower(b)
      end)
      local categories = { { key = "ALL", label = "All" } }
      local subfilters = { ALL = { { label = "All" } } }
      for _, label in ipairs(catLabels) do
        categories[#categories + 1] = { key = label, label = label }
        subfilters[label] = { { label = "All" } }
      end

      local function EnsureButton(idx, size)
        local b = buttons[idx]
        if not b then
          b = CreateFrame("Button", nil, content)
          b:SetSize(size, size)
          local t = b:CreateTexture(nil, "ARTWORK")
          t:SetAllPoints(true)
          b.tex = t
          b:SetScript("OnEnter", function(self)
            if self.__label then
              GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
              GameTooltip:SetText(self.__label)
              GameTooltip:Show()
            end
          end)
          b:SetScript("OnLeave", function() GameTooltip:Hide() end)
          buttons[idx] = b
        end
        return b
      end

      local catButtons = {}
      local subButtons = {}
      editor.textureCategoryButtons = catButtons
      editor.textureSubButtons = subButtons

      local function EnsureCatButton(idx)
        local b = catButtons[idx]
        if not b then
          b = CreateFrame("Button", nil, catContent, "UIPanelButtonTemplate")
          b:SetSize(90, 22)
          catButtons[idx] = b
        end
        return b
      end

      local y = -4
      for i, cat in ipairs(categories) do
        local b = EnsureCatButton(i)
        b:ClearAllPoints()
        b:SetPoint("TOPLEFT", 0, y)
        b:SetText(cat.label)
        b.__key = cat.key
        y = y - 26
      end
      catContent:SetSize(90, math.max(1, -y + 6))

      local function EnsureSubButton(idx)
        local b = subButtons[idx]
        if not b then
          b = CreateFrame("Button", nil, subContent, "UIPanelButtonTemplate")
          b:SetSize(120, 22)
          subButtons[idx] = b
        end
        return b
      end

      local pageSize = 130
      local page = 1
      local catKey = "ALL"
      local subKey = "All"
      local search = ""
      local cachedFilterKey = nil
      local cachedFilterList = nil

      local function FilterEntries()
        local filterKey = table.concat({
          tostring(catKey or "ALL"),
          tostring(subKey or "All"),
          tostring(search or ""),
        }, "\31")
        if cachedFilterKey == filterKey and cachedFilterList then
          return cachedFilterList
        end
        local list = {}
        for _, entry in ipairs(entries) do
          if catKey == "ALL" or entry.cat == catKey then
            if catKey == "ALL" or entry.filter == subKey then
              if search == "" or entry.search:find(search, 1, true) then
                list[#list + 1] = entry
              end
            end
          end
        end
        cachedFilterKey = filterKey
        cachedFilterList = list
        return list
      end

      local function LayoutPage(list)
        local availW = (scroll:GetWidth() or 1) - 12
        local availH = (scroll:GetHeight() or 1) - 12
        local rows, cols = 13, 10
        local pad = 4
        local size = math.max(10, math.floor((availW - pad * (cols - 1)) / cols))
        local rowH = size + pad
        local neededH = rows * rowH + 6
        local startIndex = (page - 1) * pageSize + 1
        local x0, y0 = 6, -6
        for i = 1, pageSize do
          local item = list[startIndex + i - 1]
          local b = EnsureButton(i, size)
          if item then
            local col = (i - 1) % cols
            local row = math.floor((i - 1) / cols)
            b:ClearAllPoints()
            b:SetPoint("TOPLEFT", x0 + col * (size + pad), y0 - row * rowH)
            b.tex:SetTexture(item.path)
            b.__label = item.label
            b:SetScript("OnClick", function()
              if onSelect then onSelect(item) end
              picker:Hide()
            end)
            b:Show()
          else
            b:Hide()
          end
        end
        content:SetSize(availW, neededH)
        scroll:SetVerticalScroll(0)
      end

      local function Refresh()
        local list = FilterEntries()
        local total = #list
        local pages = math.max(1, math.ceil(total / pageSize))
        if page > pages then page = pages end
        if page < 1 then page = 1 end
        pageLabel:SetText("Page " .. page .. " / " .. pages)
        if pageEdit and pageEdit.HasFocus and not pageEdit:HasFocus() then
          pageEdit:SetText(tostring(page))
        end
        LayoutPage(list)
      end

      local function RenderSubFilters()
        local list = subfilters[catKey] or { { label = "All" } }
        local yPos = -4
        for i, entry in ipairs(list) do
          local b = EnsureSubButton(i)
          b:ClearAllPoints()
          b:SetPoint("TOPLEFT", 0, yPos)
          b:SetText(entry.label)
          b:SetScript("OnClick", function()
            subKey = entry.label
            Refresh()
          end)
          b:Show()
          yPos = yPos - 26
        end
        for i = #list + 1, #subButtons do
          subButtons[i]:Hide()
        end
        subKey = list[1] and list[1].label or "All"
        subContent:SetSize(120, math.max(1, -yPos + 6))
      end

      for _, b in ipairs(catButtons) do
        b:SetScript("OnClick", function()
          catKey = b.__key
          RenderSubFilters()
          Refresh()
        end)
      end
      RenderSubFilters()

      searchBox:SetScript("OnTextChanged", function(self)
        search = string.lower(self:GetText() or "")
        page = 1
        Refresh()
      end)
      searchBox:SetScript("OnEscapePressed", function(self) self:ClearFocus() end)

      prevBtn:SetScript("OnClick", function()
        page = math.max(1, page - 1)
        Refresh()
      end)
      nextBtn:SetScript("OnClick", function()
        page = page + 1
        Refresh()
      end)
      pageEdit:SetScript("OnEnterPressed", function(self)
        local v = tonumber(self:GetText() or "")
        if v then page = v end
        Refresh()
        self:ClearFocus()
      end)
      pageEdit:SetScript("OnEscapePressed", function(self) self:ClearFocus() end)

      scroll:EnableMouseWheel(true)
      if scroll.ScrollBar then scroll.ScrollBar:Show() end
      scroll:HookScript("OnSizeChanged", function() Refresh() end)

      if editor.ApplyTheme then editor:ApplyTheme() end
      picker.Refresh = Refresh
      picker:HookScript("OnShow", function() Refresh() end)
      Refresh()
      editor.texturePicker = picker
    end

    editor.texturePicker.onSelect = onSelect
    editor.texturePicker:Show()
    if editor.texturePicker.Refresh then
      editor.texturePicker:Refresh()
    end
  end

  return {
    ShowTexturePicker = ShowTexturePicker,
  }
end
