-- LidCouncil_Editor_PanelManagement.lua
-- Split from Editor.lua to isolate panel management.

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_GetEditorPanelManagementDeps_Impl
if type(getDeps) ~= "function" then
  error("LidCouncil missing editor panel management dependencies.")
end

local deps = getDeps()
local RootDB = deps.RootDB
local DB = deps.DB
local DeepCopy = deps.DeepCopy
local Print = deps.Print
local LogSilent = deps.LogSilent
local RebuildAllPanels = deps.RebuildAllPanels
local TrimName = deps.TrimName
local ClampNameLen = deps.ClampNameLen
local MAX_PANEL_NAME = deps.MAX_PANEL_NAME
local frames = deps.Frames or {}

local sortedPanelNamesByDb = setmetatable({}, { __mode = "k" })

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

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

local function SetSelectedPanelName(value)
  deps.SetSelectedPanelName(value)
end

local function IsValidPanelName(name)
  if not name or name == "" then
    return false
  end
  return not name:find("[%c]")
end

local function NormalizePanelName(raw)
  return TrimName(raw)
end

local function RefreshPanelSelection()
  local editor = GetEditor()
  if editor and editor.RequestPanelsSectionRefresh then
    editor:RequestPanelsSectionRefresh()
  elseif editor and editor.RefreshPanelsSection then
    editor:RefreshPanelsSection()
  elseif editor and editor.Refresh then
    editor:Refresh()
  end
end

local function InvalidateSortedPanelNames(db)
  if not db then
    sortedPanelNamesByDb = setmetatable({}, { __mode = "k" })
    return
  end
  sortedPanelNamesByDb[db] = nil
end

local function GetSortedPanelNames(db)
  if sortedPanelNamesByDb[db] then
    return sortedPanelNamesByDb[db]
  end
  local names = {}
  for name in pairs((db and db.panels) or {}) do
    names[#names + 1] = name
  end
  table.sort(names, function(a, b)
    return string.lower(tostring(a or "")) < string.lower(tostring(b or ""))
  end)
  sortedPanelNamesByDb[db] = names
  return names
end

local function SelectPanel(name)
  if name and not DB().panels[name] then
    name = nil
  end
  SetSelectedPanelName(name)
  RefreshPanelSelection()
end

local function CreateNewPanelNamed(name)
  local root = RootDB()
  if root.currentProfile == "Default" then
    StaticPopup_Show("LIDCOUNCIL_NEED_PROFILE")
    return false
  end

  local db = DB()
  local raw = name
  name = NormalizePanelName(name)
  name = ClampNameLen(name, MAX_PANEL_NAME, "Panel")
  if name == "" then
    Print("Please enter a panel name.")
    return false
  end
  if raw and TrimName(raw) ~= name then
    Print("Panel name adjusted to: " .. name)
    if LogSilent then
      LogSilent("Panel name adjusted to: " .. name)
    end
  end
  if not IsValidPanelName(name) then
    Print("Invalid panel name. Please remove line breaks/control characters.")
    return false
  end
  if db.panels[name] then
    Print("A panel with that name already exists: " .. name)
    return false
  end

  db.panels[name] = {
    w = 300, h = 120,
    anchor = { "CENTER", "UIParent", "CENTER", 0, 0 },
    color = { 0.05, 0.05, 0.07, 0.75 },
    strata = "BACKGROUND",
    border = "tooltip",
    locked = false,
    gradient = nil,
    diagnostic = { fpsGraph = false },
    specialContent = {
      mode = "NONE",
      showGold = false,
      showFPS = false,
      showStats = false,
      showCustomText = false,
      gold = {
        color = { 1.00, 0.82, 0.00, 1.00 },
        font = "GameFontHighlightSmall",
        size = 14,
      },
      fps = {
        font = "GameFontHighlightSmall",
        size = 14,
        alpha = 1,
        lowValue = 30,
        highValue = 60,
        lowColor = { 0.95, 0.24, 0.24, 1.00 },
        midColor = { 1.00, 0.62, 0.16, 1.00 },
        highColor = { 0.20, 0.90, 0.20, 1.00 },
      },
      stats = {},
      statsTitleColors = {},
      statsValueColors = {},
      statsSize = 14,
      statsFont = "GameFontHighlightSmall",
      statsAlpha = 1,
      customText = {
        text = "Custom Text",
        color = { 1.00, 1.00, 1.00, 1.00 },
        font = "GameFontHighlightSmall",
        size = 14,
      },
    },
  }
  InvalidateSortedPanelNames(db)

  RebuildAllPanels()
  SelectPanel(name)
  return true
end

local function DeleteSelectedPanel()
  local panelName = GetSelectedPanelName()
  if not panelName then
    return
  end

  local db = DB()
  db.panels[panelName] = nil
  db.positions[panelName] = nil
  InvalidateSortedPanelNames(db)

  local destroyRuntime = _G.LIDCOUNCIL_DestroyPanelRuntime
  if type(destroyRuntime) == "function" then
    destroyRuntime(panelName)
  elseif frames[panelName] then
    frames[panelName]:Hide()
    frames[panelName] = nil
  end

  SetSelectedPanelName(nil)
  RebuildAllPanels()
  RefreshPanelSelection()
end

local function RenameSelectedPanel(newName)
  local selectedPanelName = GetSelectedPanelName()
  if not selectedPanelName then
    return
  end

  local raw = newName
  newName = NormalizePanelName(newName)
  newName = ClampNameLen(newName, MAX_PANEL_NAME, "Panel")
  if newName == "" then
    Print("Please enter a panel name.")
    return
  end
  if raw and TrimName(raw) ~= newName then
    Print("Panel name adjusted to: " .. newName)
    if LogSilent then
      LogSilent("Panel name adjusted to: " .. newName)
    end
  end
  if not IsValidPanelName(newName) then
    Print("Invalid panel name. Please remove line breaks/control characters.")
    return
  end
  if newName == selectedPanelName then
    return
  end

  local db = DB()
  if db.panels[newName] then
    Print("A panel with that name already exists: " .. newName)
    return
  end

  local oldCfg = db.panels[selectedPanelName]
  if not oldCfg then
    return
  end

  db.panels[newName] = DeepCopy(oldCfg)
  if db.positions[selectedPanelName] then
    db.positions[newName] = DeepCopy(db.positions[selectedPanelName])
  end

  db.panels[selectedPanelName] = nil
  db.positions[selectedPanelName] = nil
  InvalidateSortedPanelNames(db)

  if frames[selectedPanelName] then
    frames[selectedPanelName]:Hide()
    frames[selectedPanelName] = nil
  end

  SetSelectedPanelName(newName)
  RebuildAllPanels()
  RefreshPanelSelection()
end

local function CopySelectedPanelToProfile(newName, targetProfileName)
  local selectedPanelName = GetSelectedPanelName()
  if not selectedPanelName then
    return
  end

  local raw = newName
  newName = NormalizePanelName(newName)
  newName = ClampNameLen(newName, MAX_PANEL_NAME, "Panel")
  if newName == "" then
    Print("Please enter a panel name.")
    return
  end
  if raw and TrimName(raw) ~= newName then
    Print("Panel name adjusted to: " .. newName)
    if LogSilent then
      LogSilent("Panel name adjusted to: " .. newName)
    end
  end
  if not IsValidPanelName(newName) then
    Print("Invalid panel name. Please remove line breaks/control characters.")
    return
  end

  local root = RootDB()
  local sourceProfileName = root.currentProfile or "Default"
  targetProfileName = TrimName(targetProfileName or sourceProfileName)
  if targetProfileName == "" then
    Print("Please select a target profile.")
    return
  end

  local sourceDb = root.profiles[sourceProfileName]
  if sourceProfileName == root.currentProfile then
    sourceDb = DB()
  end
  sourceDb = sourceDb or { panels = {}, positions = {} }

  root.profiles[targetProfileName] = root.profiles[targetProfileName] or {
    panels = {},
    positions = {},
    spec = { auto = false, layouts = {} },
    __seeded = false,
  }
  local targetDb = root.profiles[targetProfileName]
  targetDb.panels = targetDb.panels or {}
  targetDb.positions = targetDb.positions or {}

  if targetDb.panels[newName] then
    Print("Profile \"" .. tostring(targetProfileName) .. "\" already has a panel named: " .. newName)
    return
  end

  local src = sourceDb.panels[selectedPanelName]
  if not src then
    return
  end

  targetDb.panels[newName] = DeepCopy(src)
  if sourceDb.positions and sourceDb.positions[selectedPanelName] then
    targetDb.positions[newName] = DeepCopy(sourceDb.positions[selectedPanelName])
  else
    targetDb.positions[newName] = nil
  end
  InvalidateSortedPanelNames(targetDb)

  if targetProfileName == sourceProfileName then
    RebuildAllPanels()
    SelectPanel(newName)
  else
    Print("Copied panel \"" .. tostring(selectedPanelName) .. "\" to profile \"" .. tostring(targetProfileName) .. "\" as \"" .. tostring(newName) .. "\".")
  end
end

local function CopySelectedPanel(newName)
  return CopySelectedPanelToProfile(newName, RootDB().currentProfile)
end

INTERNAL_API.LIDCOUNCIL_EditorPanelManagement_Impl = {
  InvalidateSortedPanelNames = InvalidateSortedPanelNames,
  GetSortedPanelNames = GetSortedPanelNames,
  SelectPanel = SelectPanel,
  GetSelectedPanelName = GetSelectedPanelName,
  CreateNewPanelNamed = CreateNewPanelNamed,
  DeleteSelectedPanel = DeleteSelectedPanel,
  RenameSelectedPanel = RenameSelectedPanel,
  CopySelectedPanel = CopySelectedPanel,
  CopySelectedPanelToProfile = CopySelectedPanelToProfile,
}
