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_CreatePanelModelPickerHelpers_Impl = function(deps)
  deps = type(deps) == "table" and deps or {}

  local editor = deps.editor
  local ApplyFrameSkin = deps.ApplyFrameSkin
  local HideOtherPickers = deps.HideOtherPickers
  local modelEntries = deps.modelEntries or {}
  local DB = deps.DB
  local GetSelectedPanelName = deps.GetSelectedPanelName

  local function ClampPreviewNumber(value, defaultValue, minValue, maxValue)
    local n = tonumber(value)
    if n == nil then return defaultValue end
    if minValue ~= nil and n < minValue then n = minValue end
    if maxValue ~= nil and n > maxValue then n = maxValue end
    return n
  end

  local function ShowModelPicker(onSelect)
    HideOtherPickers("modelPicker")
    if not editor.modelPicker then
      local picker = CreateFrame("Frame", "LIDCOUNCIL_ModelPicker", UIParent, "BackdropTemplate")
      picker:SetFrameStrata("DIALOG")
      picker:SetSize(860, 560)
      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 Model")

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

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

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

      local catScroll = CreateFrame("ScrollFrame", nil, catFrame, "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 listFrame = CreateFrame("Frame", nil, picker, "BackdropTemplate")
      listFrame:SetPoint("TOPLEFT", catFrame, "TOPRIGHT", 12, 0)
      listFrame:SetPoint("BOTTOMLEFT", catFrame, "BOTTOMRIGHT", 12, 0)
      listFrame:SetWidth(240)
      ApplyFrameSkin(listFrame)

      local listTitle = listFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
      listTitle:SetPoint("TOPLEFT", 10, -6)
      listTitle:SetText("Models")

      local listScroll = CreateFrame("ScrollFrame", nil, listFrame, "UIPanelScrollFrameTemplate")
      listScroll:SetPoint("TOPLEFT", 6, -24)
      listScroll:SetPoint("BOTTOMRIGHT", -22, 6)
      listScroll:EnableMouseWheel(true)
      listScroll:SetScript("OnMouseWheel", function(self, delta)
        local cur = self:GetVerticalScroll() or 0
        self:SetVerticalScroll(cur - (delta * 20))
      end)

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

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

      local searchLabel = picker:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
      searchLabel:SetPoint("TOPLEFT", listFrame, "TOPLEFT", 0, 26)
      searchLabel:SetText("Search:")

      local searchBox = CreateFrame("EditBox", nil, picker, "InputBoxTemplate")
      searchBox:SetSize(240, 20)
      searchBox:SetPoint("LEFT", searchLabel, "RIGHT", 6, 0)
      searchBox:SetAutoFocus(false)
      searchBox:SetText("")

      local searchBtn = CreateFrame("Button", nil, picker, "UIPanelButtonTemplate")
      searchBtn:SetSize(70, 20)
      searchBtn:SetPoint("LEFT", searchBox, "RIGHT", 6, 0)
      searchBtn:SetText("Search")

      local prevBtn = CreateFrame("Button", nil, picker, "UIPanelButtonTemplate")
      prevBtn:SetSize(28, 20)
      prevBtn:SetPoint("BOTTOMLEFT", listFrame, "BOTTOMLEFT", 0, -28)
      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 previewTitle = previewFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
      previewTitle:SetPoint("TOPLEFT", 10, -10)
      previewTitle:SetText("Preview")

      local previewId = previewFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
      previewId:SetPoint("TOPLEFT", previewTitle, "BOTTOMLEFT", 0, -2)
      previewId:SetText("ID: -")

      local controls = CreateFrame("Frame", nil, previewFrame)
      controls:SetPoint("BOTTOMLEFT", 6, 6)
      controls:SetPoint("BOTTOMRIGHT", -6, 6)
      controls:SetHeight(130)

      local previewModel = CreateFrame("PlayerModel", nil, previewFrame)
      previewModel:SetPoint("TOPLEFT", 6, -30)
      previewModel:SetPoint("BOTTOMRIGHT", controls, "TOPRIGHT", 0, 6)
      previewModel:SetPortraitZoom(0)
      previewModel:SetModelScale(1)

      local zoomSlider = CreateFrame("Slider", "LIDCOUNCIL_ModelZoomSlider", controls, "OptionsSliderTemplate")
      zoomSlider:SetPoint("TOPLEFT", 0, -6)
      zoomSlider:SetWidth(180)
      zoomSlider:SetMinMaxValues(0.25, 4.0)
      zoomSlider:SetValueStep(0.05)
      zoomSlider:SetObeyStepOnDrag(true)
      _G[zoomSlider:GetName() .. "Low"]:SetText("0.25")
      _G[zoomSlider:GetName() .. "High"]:SetText("4.0")
      _G[zoomSlider:GetName() .. "Text"]:SetText("Zoom")

      local rotSlider = CreateFrame("Slider", "LIDCOUNCIL_ModelRotateSlider", controls, "OptionsSliderTemplate")
      rotSlider:SetPoint("TOPLEFT", 200, -6)
      rotSlider:SetWidth(180)
      rotSlider:SetMinMaxValues(0, 360)
      rotSlider:SetValueStep(5)
      rotSlider:SetObeyStepOnDrag(true)
      _G[rotSlider:GetName() .. "Low"]:SetText("0")
      _G[rotSlider:GetName() .. "High"]:SetText("360")
      _G[rotSlider:GetName() .. "Text"]:SetText("Rotate")

      local xSlider = CreateFrame("Slider", "LIDCOUNCIL_ModelXOffsetSlider", controls, "OptionsSliderTemplate")
      xSlider:SetPoint("TOPLEFT", 0, -52)
      xSlider:SetWidth(180)
      xSlider:SetMinMaxValues(-2, 2)
      xSlider:SetValueStep(0.05)
      xSlider:SetObeyStepOnDrag(true)
      _G[xSlider:GetName() .. "Low"]:SetText("-2")
      _G[xSlider:GetName() .. "High"]:SetText("2")
      _G[xSlider:GetName() .. "Text"]:SetText("X Offset")

      local ySlider = CreateFrame("Slider", "LIDCOUNCIL_ModelYOffsetSlider", controls, "OptionsSliderTemplate")
      ySlider:SetPoint("TOPLEFT", 200, -52)
      ySlider:SetWidth(180)
      ySlider:SetMinMaxValues(-2, 2)
      ySlider:SetValueStep(0.05)
      ySlider:SetObeyStepOnDrag(true)
      _G[ySlider:GetName() .. "Low"]:SetText("-2")
      _G[ySlider:GetName() .. "High"]:SetText("2")
      _G[ySlider:GetName() .. "Text"]:SetText("Y Offset")

      local resetBtn = CreateFrame("Button", nil, controls, "UIPanelButtonTemplate")
      resetBtn:SetSize(90, 20)
      resetBtn:SetPoint("TOPRIGHT", controls, "TOPRIGHT", -6, -92)
      resetBtn:SetText("Reset")

      local applyBtn = CreateFrame("Button", nil, controls, "UIPanelButtonTemplate")
      applyBtn:SetSize(90, 20)
      applyBtn:SetPoint("RIGHT", resetBtn, "LEFT", -8, 0)
      applyBtn:SetText("Apply")

      local entries = modelEntries
      local selectedItem = nil
      local previewState = { zoom = 1.0, facing = 0, x = 0, y = 0 }

      for _, entry in ipairs(entries) do
        if not entry.search then
          local label = entry.label or ("Model " .. tostring(entry.id))
          local path = entry.path or ""
          entry.search = string.lower(label .. " " .. tostring(entry.id or "") .. " " .. path)
        end
        local cat = entry.cat or "Other"
        if type(cat) == "string" and string.lower(cat) == "fog" then
          cat = "Fog"
        end
        entry.cat = cat
      end

      if GetSelectedPanelName() then
        local panel = DB().panels[GetSelectedPanelName()]
        if panel and panel.bgModelId then
          for _, entry in ipairs(entries) do
            if entry.id == panel.bgModelId then
              selectedItem = entry
              break
            end
          end
        end
        if panel and panel.bgModelSettings then
          previewState.zoom = panel.bgModelSettings.zoom or 1.0
          previewState.facing = panel.bgModelSettings.facing or 0
          previewState.x = panel.bgModelSettings.x or 0
          previewState.y = panel.bgModelSettings.y or 0
        end
      end

      local listButtons = {}
      editor.modelListButtons = listButtons

      local function ApplyPreviewTransform()
        previewModel:SetModelScale(ClampPreviewNumber(previewState.zoom, 1, 0.05, 10))
        previewModel:SetFacing(math.rad(ClampPreviewNumber(previewState.facing, 0, -360, 360)))
        previewModel:SetPosition(
          ClampPreviewNumber(previewState.x, 0, -10000, 10000),
          ClampPreviewNumber(previewState.y, 0, -10000, 10000),
          0
        )
      end

      local function SetPreview(item)
        local modelId = item and tonumber(item.id)
        if not item or not modelId or modelId <= 0 then
          previewModel:ClearModel()
          previewTitle:SetText("Preview")
          previewId:SetText("ID: -")
          return
        end
        previewTitle:SetText(item.label or ("Model " .. tostring(modelId)))
        previewId:SetText("ID: " .. tostring(modelId))
        local ok = pcall(function()
          previewModel:SetModel(modelId)
        end)
        if not ok then
          previewModel:ClearModel()
          return
        end
        ApplyPreviewTransform()
      end

      local function EnsureListButton(idx)
        local b = listButtons[idx]
        if not b then
          b = CreateFrame("Button", nil, listContent, "UIPanelButtonTemplate")
          b:SetSize(190, 22)
          b:SetNormalFontObject("GameFontHighlightSmall")
          local border = CreateFrame("Frame", nil, b, "BackdropTemplate")
          border:SetPoint("TOPLEFT", -1, 1)
          border:SetPoint("BOTTOMRIGHT", 1, -1)
          border:SetBackdrop({ edgeFile = "Interface/Buttons/WHITE8x8", edgeSize = 1 })
          border:SetBackdropBorderColor(1, 1, 1, 0.9)
          border:Hide()
          b.__selBorder = border
          b:SetScript("OnEnter", function(self)
            if self.__item then SetPreview(self.__item) end
          end)
          b:SetScript("OnClick", function(self)
            if self.__item then
              selectedItem = self.__item
              SetPreview(self.__item)
              for _, other in ipairs(listButtons) do
                if other.__selBorder then other.__selBorder:Hide() end
              end
              if self.__selBorder then self.__selBorder:Show() end
            end
          end)
          listButtons[idx] = b
          if editor.ApplyTheme then editor:ApplyTheme() end
        end
        return b
      end

      local catLabels = {}
      local catSeen = {}
      for _, entry in ipairs(entries) do
        local cat = entry.cat or "Other"
        if cat ~= "" and 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" } }
      for _, label in ipairs(catLabels) do
        categories[#categories + 1] = { key = label, label = label }
      end
      local catButtons = {}
      editor.modelCategoryButtons = catButtons

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

      local pageSize = 100
      local page = 1
      local catKey = "ALL"
      local search = ""
      local cachedFilterKey = nil
      local cachedFilterList = nil

      local function FilterEntries()
        local filterKey = table.concat({
          tostring(catKey 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 search == "" or (entry.search and entry.search:find(search, 1, true)) then
              list[#list + 1] = entry
            end
          end
        end
        cachedFilterKey = filterKey
        cachedFilterList = list
        return list
      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 not pageEdit:HasFocus() then
          pageEdit:SetText(tostring(page))
        end
        local startIndex = (page - 1) * pageSize + 1
        local yPos = -4
        for i = 1, pageSize do
          local item = list[startIndex + i - 1]
          local b = EnsureListButton(i)
          if item then
            b:ClearAllPoints()
            b:SetPoint("TOPLEFT", 0, yPos)
            b:SetText(item.label or ("Model " .. tostring(item.id)))
            b.__item = item
            if selectedItem and selectedItem.id == item.id then
              if b.SetTextColor then b:SetTextColor(0.30, 0.80, 1.00) end
              if b.__selBorder then b.__selBorder:Show() end
            else
              if b.SetTextColor then b:SetTextColor(1, 1, 1) end
              if b.__selBorder then b.__selBorder:Hide() end
            end
            b:Show()
            yPos = yPos - 24
          else
            b:Hide()
          end
        end
        listContent:SetSize(190, math.max(1, -yPos + 6))
        listScroll:SetVerticalScroll(0)
      end

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

      local function DoSearch()
        search = string.lower(searchBox:GetText() or "")
        page = 1
        Refresh()
      end

      searchBtn:SetScript("OnClick", DoSearch)
      searchBox:SetScript("OnEnterPressed", function(self)
        DoSearch()
        self:ClearFocus()
      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)

      zoomSlider:SetValue(previewState.zoom)
      rotSlider:SetValue(previewState.facing)
      xSlider:SetValue(previewState.x)
      ySlider:SetValue(previewState.y)

      zoomSlider:SetScript("OnValueChanged", function(_, val)
        previewState.zoom = val
        ApplyPreviewTransform()
      end)
      rotSlider:SetScript("OnValueChanged", function(_, val)
        previewState.facing = val
        ApplyPreviewTransform()
      end)
      xSlider:SetScript("OnValueChanged", function(_, val)
        previewState.x = val
        ApplyPreviewTransform()
      end)
      ySlider:SetScript("OnValueChanged", function(_, val)
        previewState.y = val
        ApplyPreviewTransform()
      end)

      resetBtn:SetScript("OnClick", function()
        previewState.zoom = 1.0
        previewState.facing = 0
        previewState.x = 0
        previewState.y = 0
        zoomSlider:SetValue(1.0)
        rotSlider:SetValue(0)
        xSlider:SetValue(0)
        ySlider:SetValue(0)
        ApplyPreviewTransform()
      end)

      applyBtn:SetScript("OnClick", function()
        if not selectedItem then return end
        if onSelect then
          onSelect(selectedItem, {
            zoom = previewState.zoom,
            facing = previewState.facing,
            x = previewState.x,
            y = previewState.y,
          })
        end
        picker:Hide()
      end)

      listFrame:SetScript("OnLeave", function()
        if selectedItem then ApplyPreviewTransform() end
      end)
      previewFrame:SetScript("OnEnter", function()
        if selectedItem then ApplyPreviewTransform() end
      end)

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

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

  return {
    ShowModelPicker = ShowModelPicker,
  }
end
