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 RequireApi = INTERNAL_API.LIDCOUNCIL_RequireApi_Impl
if type(RequireApi) ~= "function" then
  error("LidCouncil missing shared editor page helpers.")
end

local RootDB = RequireApi("LIDCOUNCIL_RootDB", _G.LIDCOUNCIL_RootDB)
local DB = RequireApi("LIDCOUNCIL_DB", _G.LIDCOUNCIL_DB)
local ApplyFrameSkin = RequireApi("LIDCOUNCIL_ApplyFrameSkin", _G.LIDCOUNCIL_ApplyFrameSkin)
local GetBackgroundPath = RequireApi("LIDCOUNCIL_GetBackgroundPath", _G.LIDCOUNCIL_GetBackgroundPath)
local RebuildAllPanels = RequireApi("LIDCOUNCIL_RebuildAllPanels", _G.LIDCOUNCIL_RebuildAllPanels)
local GetSelectedPanelName = RequireApi("LIDCOUNCIL_GetSelectedPanelName", _G.LIDCOUNCIL_GetSelectedPanelName)
local CreatePanelIconPickerHelpers = INTERNAL_API.LIDCOUNCIL_CreatePanelIconPickerHelpers_Impl
local CreatePanelTexturePickerHelpers = INTERNAL_API.LIDCOUNCIL_CreatePanelTexturePickerHelpers_Impl
local CreatePanelModelPickerHelpers = INTERNAL_API.LIDCOUNCIL_CreatePanelModelPickerHelpers_Impl
if type(CreatePanelIconPickerHelpers) ~= "function"
  or type(CreatePanelTexturePickerHelpers) ~= "function"
  or type(CreatePanelModelPickerHelpers) ~= "function" then
  error("LidCouncil missing panel asset picker helpers.")
end

local LogSilent = rawget(_G, "LIDCOUNCIL_LogSilent")

local function RefreshPanelProperties(editor)
  if editor and editor.RequestPanelPropertiesRefresh then
    editor:RequestPanelPropertiesRefresh()
  elseif editor and editor.RefreshPanelPropertiesSection then
    editor:RefreshPanelPropertiesSection()
  elseif editor and editor.RefreshPanelsSection then
    editor:RefreshPanelsSection()
  elseif editor and editor.Refresh then
    editor:Refresh()
  end
end

local function CreatePanelAssetPickers(editor, deps)
  if not editor then
    return {}
  end

  deps = deps or {}
  local bgPreview = deps.bgPreview
  local texturePickBtn = deps.texturePickBtn
  local iconPickBtn = deps.iconPickBtn
  local modelPickBtn = deps.modelPickBtn
  local textureEntries = deps.textureEntries or {}
  local modelEntries = deps.modelEntries or {}
  local clearPanelBackgroundState = deps.ClearPanelBackgroundState

  local function ClearBackgroundState(panel)
    if not panel then return end
    if type(clearPanelBackgroundState) == "function" then
      clearPanelBackgroundState(panel)
      return
    end
    panel.bg = "NONE"
    panel.bgType = nil
    panel.bgIconName = nil
    panel.bgTextureName = nil
    panel.bgModelId = nil
    panel.bgModelName = nil
    panel.bgModelSettings = nil
    panel.bgTexCoord = nil
    panel.bgChoiceKey = nil
  end

  local function HideOtherPickers(activeKey)
    local keys = { "iconPicker", "texturePicker", "modelPicker" }
    for _, key in ipairs(keys) do
      if key ~= activeKey and editor[key] then
        editor[key]:Hide()
      end
    end
  end

  local panelIconPickerHelpers = CreatePanelIconPickerHelpers({
    editor = editor,
    ApplyFrameSkin = ApplyFrameSkin,
    HideOtherPickers = HideOtherPickers,
    LogSilent = LogSilent,
  })
  local ShowIconPicker = panelIconPickerHelpers.ShowIconPicker
  local function BuildCustomBackgroundOptions()
    local options = { { text = "None", value = "NONE" } }
    local customEntries = {}
    local root = RootDB and RootDB()
    if root and root.backgroundCategories then
      for _, cat in ipairs(root.backgroundCategories) do
        if cat.items then
          for _, name in ipairs(cat.items) do
            if type(name) == "string" and name ~= "" then
              local path = (GetBackgroundPath and GetBackgroundPath(name))
                or ("Interface\\AddOns\\LidCouncil_UserMedia\\Your_Backgrounds\\" .. name .. ".tga")
              customEntries[#customEntries + 1] = { text = name, value = path }
            end
          end
        end
      end
    end
    table.sort(customEntries, function(a, b)
      local aText = string.lower(tostring((a and a.text) or ""))
      local bText = string.lower(tostring((b and b.text) or ""))
      if aText == bText then
        return string.lower(tostring((a and a.value) or "")) < string.lower(tostring((b and b.value) or ""))
      end
      return aText < bText
    end)
    for _, entry in ipairs(customEntries) do
      options[#options + 1] = entry
    end
    return options
  end

  local function CopyTexCoord(texCoord)
    if type(texCoord) ~= "table" then return nil end
    local u1 = tonumber(texCoord[1])
    local u2 = tonumber(texCoord[2])
    local v1 = tonumber(texCoord[3])
    local v2 = tonumber(texCoord[4])
    if not (u1 and u2 and v1 and v2) then return nil end
    return { u1, u2, v1, v2 }
  end

  local function SameTexCoord(a, b)
    if a == nil and b == nil then return true end
    if type(a) ~= "table" or type(b) ~= "table" then return false end
    for i = 1, 4 do
      local av = tonumber(a[i]) or 0
      local bv = tonumber(b[i]) or 0
      if math.abs(av - bv) > 0.0001 then
        return false
      end
    end
    return true
  end

  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 SafeSetPreviewTexture(texture, path, texCoord)
    if not texture or not path or path == "NONE" then
      return false
    end
    local ok = pcall(texture.SetTexture, texture, path)
    if not ok then
      texture:SetTexture(nil)
      return false
    end
    if type(texCoord) == "table" then
      texture:SetTexCoord(
        ClampPreviewNumber(texCoord[1], 0, 0, 1),
        ClampPreviewNumber(texCoord[2], 1, 0, 1),
        ClampPreviewNumber(texCoord[3], 0, 0, 1),
        ClampPreviewNumber(texCoord[4], 1, 0, 1)
      )
    else
      texture:SetTexCoord(0, 1, 0, 1)
    end
    return true
  end

  local function FindTalentOptionForPanel(panel, options)
    if type(panel) ~= "table" or type(options) ~= "table" then return nil end
    if panel.bgChoiceKey then
      for _, opt in ipairs(options) do
        if opt and opt.value == panel.bgChoiceKey then
          return opt
        end
      end
    end
    for _, opt in ipairs(options) do
      if opt and opt.bg == panel.bg and SameTexCoord(opt.texCoord, panel.bgTexCoord) then
        return opt
      end
    end
    return nil
  end

  local function UpdateBgPreview(path, texCoord)
    if not bgPreview or not bgPreview.texture then
      return
    end
    if not path or path == "NONE" then
      bgPreview:Hide()
      return
    end
    if SafeSetPreviewTexture(bgPreview.texture, path, texCoord) then
      bgPreview:Show()
    else
      bgPreview:Hide()
    end
  end

  local function SetPanelBackground(value, kind, label, modelSettings, texCoord, choiceKey)
    if not GetSelectedPanelName() then return end
    local p = DB().panels[GetSelectedPanelName()]
    if not p then return end
    p.color = p.color or { 0.05, 0.05, 0.07, 0.8 }
    if kind == "TALENT" or kind == "CUSTOM" then
      p.designMode = "BG"
    elseif kind == "TEX" or kind == "ICON" or kind == "MODEL" then
      p.designMode = kind
    end

    if value == "NONE" then
      ClearBackgroundState(p)
    else
      p.bg = value
      p.bgType = kind
      if kind == "ICON" then
        p.bgIconName = label
        p.bgTextureName = nil
        p.bgModelId = nil
        p.bgModelName = nil
        p.bgModelSettings = nil
        p.bgTexCoord = nil
        p.bgChoiceKey = nil
      elseif kind == "TEX" then
        p.bgTextureName = label
        p.bgIconName = nil
        p.bgModelId = nil
        p.bgModelName = nil
        p.bgModelSettings = nil
        p.bgTexCoord = nil
        p.bgChoiceKey = nil
      elseif kind == "MODEL" then
        p.bgModelId = value
        p.bgModelName = label
        p.bgIconName = nil
        p.bgTextureName = nil
        local s = modelSettings or p.bgModelSettings or {}
        p.bgModelSettings = {
          zoom = s.zoom or 1,
          facing = s.facing or 0,
          x = s.x or 0,
          y = s.y or 0,
        }
        p.bgTexCoord = nil
        p.bgChoiceKey = nil
      elseif kind == "TALENT" then
        p.bgIconName = nil
        p.bgTextureName = nil
        p.bgModelId = nil
        p.bgModelName = nil
        p.bgModelSettings = nil
        p.bgTexCoord = CopyTexCoord(texCoord)
        p.bgChoiceKey = choiceKey
      else
        p.bgIconName = nil
        p.bgTextureName = nil
        p.bgModelId = nil
        p.bgModelName = nil
        p.bgModelSettings = nil
        p.bgTexCoord = nil
        p.bgChoiceKey = nil
      end
      p.gradient = nil
    end

    if p.designMode == "MODEL" then
      if bgPreview then bgPreview:Hide() end
    else
      UpdateBgPreview(p.bg, p.bgTexCoord)
    end
    RebuildAllPanels()
    RefreshPanelProperties(editor)
  end

  local panelTexturePickerHelpers = CreatePanelTexturePickerHelpers({
    editor = editor,
    ApplyFrameSkin = ApplyFrameSkin,
    HideOtherPickers = HideOtherPickers,
    textureEntries = textureEntries,
  })
  local ShowTexturePicker = panelTexturePickerHelpers.ShowTexturePicker
  local panelModelPickerHelpers = CreatePanelModelPickerHelpers({
    editor = editor,
    ApplyFrameSkin = ApplyFrameSkin,
    HideOtherPickers = HideOtherPickers,
    modelEntries = modelEntries,
    DB = DB,
    GetSelectedPanelName = GetSelectedPanelName,
  })
  local ShowModelPicker = panelModelPickerHelpers.ShowModelPicker
  editor.ShowIconPicker = ShowIconPicker

  if iconPickBtn then
    iconPickBtn:SetScript("OnClick", function()
      ShowIconPicker(function(icon)
        if not icon or not icon.texture then return end
        SetPanelBackground(icon.texture, "ICON", icon.label)
      end)
    end)
  end

  if texturePickBtn then
    texturePickBtn:SetScript("OnClick", function()
      ShowTexturePicker(function(item)
        if not item or not item.path then return end
        SetPanelBackground(item.path, "TEX", item.label)
      end)
    end)
  end

  if modelPickBtn then
    modelPickBtn:SetScript("OnClick", function()
      ShowModelPicker(function(item, settings)
        if not item or not item.id then return end
        SetPanelBackground(item.id, "MODEL", item.label, settings)
      end)
    end)
  end

  return {
    BuildCustomBackgroundOptions = BuildCustomBackgroundOptions,
    CopyTexCoord = CopyTexCoord,
    SameTexCoord = SameTexCoord,
    FindTalentOptionForPanel = FindTalentOptionForPanel,
    UpdateBgPreview = UpdateBgPreview,
    SetPanelBackground = SetPanelBackground,
  }
end

INTERNAL_API.LIDCOUNCIL_CreatePanelAssetPickers_Impl = CreatePanelAssetPickers
