-- LidCouncil_Editor_FloatingWindows.lua
-- Split from Editor.lua to isolate log/export/import floating windows.

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

local deps = getDeps()
local GetDebugStore = deps.GetDebugStore
local ApplyFrameSkin = deps.ApplyFrameSkin
local Print = deps.Print

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

local function PublishApi(name, value)
  _G[name] = value
  API[name] = value
end

local function CreateScrollEditBox(parent, width, height)
  local bg = CreateFrame("Frame", nil, parent, "BackdropTemplate")
  bg:SetSize(width, height)
  bg:SetBackdrop({
    bgFile = "Interface/Buttons/WHITE8x8",
    edgeFile = "Interface/Buttons/WHITE8x8",
    tile = false,
    edgeSize = 1,
    insets = { left = 1, right = 1, top = 1, bottom = 1 },
  })
  bg:SetBackdropColor(0.05, 0.05, 0.07, 0.85)
  bg:SetBackdropBorderColor(0, 0, 0, 0.9)

  local scroll = CreateFrame("ScrollFrame", nil, bg, "UIPanelScrollFrameTemplate")
  scroll:SetPoint("TOPLEFT", 6, -6)
  scroll:SetPoint("BOTTOMRIGHT", -28, 6)

  local content = CreateFrame("Frame", nil, scroll)
  content:SetSize(width - 40, height - 12)
  scroll:SetScrollChild(content)
  bg.contentFrame = content

  local edit = CreateFrame("EditBox", nil, content, "InputBoxTemplate")
  edit:SetMultiLine(true)
  edit:SetAutoFocus(false)
  edit:EnableKeyboard(true)
  edit:EnableMouse(true)
  if edit.SetTextInsets then
    edit:SetTextInsets(6, 6, 4, 4)
  end
  edit:SetFontObject(ChatFontNormal)
  edit:SetJustifyH("LEFT")
  edit:SetJustifyV("TOP")
  edit:SetWidth(width - 40)
  edit:SetHeight(height - 12)
  edit:SetPoint("TOPLEFT", 0, 0)
  if edit.SetMaxLetters then
    edit:SetMaxLetters(0)
  end
  edit.__lidPendingChars = {}
  edit.__lidPendingCount = 0
  edit.__lidCapturedPaste = nil
  edit:SetScript("OnMouseDown", function(self)
    self:SetFocus()
  end)
  edit:SetScript("OnShow", function(self)
    self:Enable()
  end)
  edit:SetScript("OnEscapePressed", function(self)
    self:ClearFocus()
  end)

  local function UpdateMetrics()
    if not edit or not scroll or not content then
      return
    end
    local minHeight = math.max(24, height - 12)
    local textHeight = minHeight
    if type(edit.GetStringHeight) == "function" then
      textHeight = math.ceil(tonumber(edit:GetStringHeight()) or 0)
    end
    if edit.__lidPreviewText and type(edit.__lidPreviewText.GetStringHeight) == "function" then
      textHeight = math.max(textHeight, math.ceil(tonumber(edit.__lidPreviewText:GetStringHeight()) or 0))
    end
    local resolvedHeight = math.max(minHeight, textHeight + 12)
    edit:SetHeight(resolvedHeight)
    content:SetHeight(resolvedHeight)
    scroll:UpdateScrollChildRect()
  end

  edit:SetScript("OnTextChanged", function(self, userInput)
    if userInput and self.__lidCapturedPaste and (self:GetText() or "") ~= self.__lidCapturedPaste then
      self.__lidCapturedPaste = nil
    end
    UpdateMetrics()
  end)
  edit:SetScript("OnCursorChanged", function(_, _, y, _, cursorHeight)
    local scrollY = scroll:GetVerticalScroll() or 0
    local visibleBottom = scrollY + scroll:GetHeight()
    local cursorBottom = (y or 0) + (cursorHeight or 0) + 12
    if cursorBottom > visibleBottom then
      scroll:SetVerticalScroll(math.max(0, cursorBottom - scroll:GetHeight()))
    elseif (y or 0) < scrollY then
      scroll:SetVerticalScroll(math.max(0, y or 0))
    end
  end)
  edit:SetScript("OnChar", function(self, char)
    local pending = self.__lidPendingChars
    pending[#pending + 1] = char
    self.__lidPendingCount = (self.__lidPendingCount or 0) + 1
    if self.__lidPasteFlushScheduled then
      return
    end
    self.__lidPasteFlushScheduled = true
    self:SetScript("OnUpdate", function(editBox)
      editBox:SetScript("OnUpdate", nil)
      editBox.__lidPasteFlushScheduled = nil
      local count = tonumber(editBox.__lidPendingCount) or 0
      local chunk = table.concat(editBox.__lidPendingChars or {})
      if type(wipe) == "function" then
        wipe(editBox.__lidPendingChars)
      else
        editBox.__lidPendingChars = {}
      end
      editBox.__lidPendingCount = 0
      if count > 1 and (editBox:GetText() or "") == "" and chunk ~= "" then
        editBox:SetText(chunk)
        editBox:SetCursorPosition(#chunk)
        editBox.__lidCapturedPaste = chunk
      end
    end)
  end)

  bg.editBox = edit
  bg.scrollFrame = scroll
  bg.UpdateMetrics = UpdateMetrics
  return bg, edit
end

local exportWin
local importWin
local settingsImportWin
local errorWin
local silentWin

local function ShowErrorLogWindow()
  if not errorWin then
    errorWin = CreateFrame("Frame", "LIDCOUNCIL_ErrorLogWindow", UIParent, "BackdropTemplate")
    errorWin:SetFrameStrata("DIALOG")
    errorWin:SetSize(540, 360)
    errorWin:SetClampedToScreen(true)
    ApplyFrameSkin(errorWin)

    local title = errorWin:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    title:SetPoint("TOPLEFT", 12, -10)
    title:SetText("Lid Error Log")
    errorWin.title = title

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

    local boxFrame, boxEdit = CreateScrollEditBox(errorWin, 510, 250)
    boxFrame:SetPoint("TOPLEFT", 12, -40)
    errorWin.boxEdit = boxEdit

    local copyHint = errorWin:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    copyHint:SetPoint("BOTTOMLEFT", 12, 18)
    copyHint:SetText("Select the text, then press Ctrl+C to copy it.")
    errorWin.copyHint = copyHint

    local selectAll = CreateFrame("Button", nil, errorWin, "UIPanelButtonTemplate")
    selectAll:SetSize(100, 22)
    selectAll:SetPoint("BOTTOMRIGHT", -120, 12)
    selectAll:SetText("Select All")
    selectAll:SetScript("OnClick", function()
      local edit = errorWin.boxEdit
      if edit then
        edit:Enable()
        edit:SetFocus()
        edit:HighlightText()
      end
    end)
    errorWin.selectAll = selectAll

    local ok = CreateFrame("Button", nil, errorWin, "UIPanelButtonTemplate")
    ok:SetSize(100, 22)
    ok:SetPoint("BOTTOMRIGHT", -12, 12)
    ok:SetText("OK")
    ok:SetScript("OnClick", function()
      errorWin:Hide()
    end)
  end

  local lines = {}
  local debugStore = GetDebugStore()
  if debugStore and debugStore.errors and #debugStore.errors > 0 then
    for _, msg in ipairs(debugStore.errors) do
      lines[#lines + 1] = tostring(msg)
    end
  else
    lines[1] = "No errors captured."
  end

  errorWin.boxEdit:SetText(table.concat(lines, "\n\n"))
  errorWin.boxEdit:SetCursorPosition(0)
  errorWin.boxEdit:HighlightText()
  errorWin.boxEdit:SetFocus()

  errorWin:ClearAllPoints()
  errorWin:SetPoint("CENTER", UIParent, "CENTER", 220, 0)
  errorWin:Show()
end

local function ShowSilentLogWindow()
  if not silentWin then
    silentWin = CreateFrame("Frame", "LIDCOUNCIL_SilentLogWindow", UIParent, "BackdropTemplate")
    silentWin:SetFrameStrata("DIALOG")
    silentWin:SetSize(540, 360)
    silentWin:SetClampedToScreen(true)
    ApplyFrameSkin(silentWin)

    local title = silentWin:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    title:SetPoint("TOPLEFT", 12, -10)
    title:SetText("Lid Silent Error Log")
    silentWin.title = title

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

    local boxFrame, boxEdit = CreateScrollEditBox(silentWin, 510, 250)
    boxFrame:SetPoint("TOPLEFT", 12, -40)
    silentWin.boxEdit = boxEdit

    local ok = CreateFrame("Button", nil, silentWin, "UIPanelButtonTemplate")
    ok:SetSize(100, 22)
    ok:SetPoint("BOTTOMRIGHT", -12, 12)
    ok:SetText("OK")
    ok:SetScript("OnClick", function()
      silentWin:Hide()
    end)
  end

  local lines = {}
  local debugStore = GetDebugStore()
  if debugStore and debugStore.silent and #debugStore.silent > 0 then
    for _, msg in ipairs(debugStore.silent) do
      lines[#lines + 1] = tostring(msg)
    end
  else
    lines[1] = "No silent errors captured."
  end

  silentWin.boxEdit:SetText(table.concat(lines, "\n\n"))
  silentWin.boxEdit:HighlightText()
  silentWin.boxEdit:SetFocus()

  silentWin:ClearAllPoints()
  silentWin:SetPoint("CENTER", UIParent, "CENTER", 220, 0)
  silentWin:Show()
end

local function PrepareFloatingPopupWindow(win)
  if not win or win.__lidFloatingPrepared then
    return
  end
  win.__lidFloatingPrepared = true
  win:SetMovable(true)
  win:EnableMouse(true)
  win:RegisterForDrag("LeftButton")
  win:SetToplevel(true)
  win:SetFrameStrata("FULLSCREEN_DIALOG")
  win:SetScript("OnDragStart", function(self)
    self:StartMoving()
  end)
  win:SetScript("OnDragStop", function(self)
    self:StopMovingOrSizing()
  end)
end

local function RaiseFloatingPopupWindow(win)
  if not win then
    return
  end
  PrepareFloatingPopupWindow(win)
  local baseLevel = 200
  local editor = GetEditor()
  if editor and editor.GetFrameLevel then
    baseLevel = math.max(baseLevel, (editor:GetFrameLevel() or 1) + 40)
  end
  win:SetFrameLevel(baseLevel)
  if win.Raise then
    win:Raise()
  end
end

local function ShowExportWindow(profileName, exportString, displayOptions)
  displayOptions = type(displayOptions) == "table" and displayOptions or {}
  if not exportWin then
    exportWin = CreateFrame("Frame", "LIDCOUNCIL_ExportWindow", UIParent, "BackdropTemplate")
    exportWin:SetSize(540, 320)
    exportWin:SetClampedToScreen(true)
    ApplyFrameSkin(exportWin)
    PrepareFloatingPopupWindow(exportWin)

    local title = exportWin:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    title:SetPoint("TOPLEFT", 12, -10)
    exportWin.title = title

    CreateFrame("Button", nil, exportWin, "UIPanelCloseButton"):SetPoint("TOPRIGHT", -2, -2)

    local boxFrame, boxEdit = CreateScrollEditBox(exportWin, 510, 220)
    boxFrame:SetPoint("TOPLEFT", 12, -40)
    exportWin.boxEdit = boxEdit

    local closeBtn = CreateFrame("Button", nil, exportWin, "UIPanelButtonTemplate")
    closeBtn:SetSize(100, 22)
    closeBtn:SetPoint("BOTTOMRIGHT", -12, 12)
    closeBtn:SetText("Close")
    closeBtn:SetScript("OnClick", function()
      exportWin:Hide()
    end)
    exportWin.closeBtn = closeBtn

    local copyBtn = CreateFrame("Button", nil, exportWin, "UIPanelButtonTemplate")
    copyBtn:SetSize(100, 22)
    copyBtn:SetPoint("RIGHT", closeBtn, "LEFT", -8, 0)
    copyBtn:SetText("Copy String")
    copyBtn:SetScript("OnClick", function()
      if exportWin and exportWin.boxEdit then
        exportWin.boxEdit:SetFocus()
        exportWin.boxEdit:HighlightText()
        Print(exportWin.copyMessage or "String selected. Press CTRL+C now to copy it.")
      end
    end)
    exportWin.copyBtn = copyBtn
  end

  if importWin and importWin:IsShown() then
    importWin:Hide()
  end

  exportWin.title:SetText(tostring(displayOptions.title or ("Lid Export: " .. tostring(profileName))))
  exportWin.copyBtn:SetText(tostring(displayOptions.copyButtonText or "Copy String"))
  exportWin.copyMessage = tostring(displayOptions.copyMessage or "String selected. Press CTRL+C now to copy it.")
  exportWin.boxEdit:SetText(exportString or "")
  exportWin.boxEdit:HighlightText()
  exportWin.boxEdit:SetFocus()

  RaiseFloatingPopupWindow(exportWin)
  if not exportWin.__lidPlaced then
    exportWin.__lidPlaced = true
    exportWin:ClearAllPoints()
    exportWin:SetPoint("CENTER", UIParent, "CENTER", 220, 0)
  end
  exportWin:Show()
end

local function ShowCopyTextWindow(title, text)
  ShowExportWindow(title, text, {
    title = tostring(title or "LidCouncil Report"),
    copyButtonText = "Select All",
    copyMessage = "Report selected. Press CTRL+C now to copy it.",
  })
end

local function ShowImportWindow(onImport, opts)
  opts = type(opts) == "table" and opts or {}
  if not importWin then
    importWin = CreateFrame("Frame", "LIDCOUNCIL_ImportWindow", UIParent, "BackdropTemplate")
    importWin:SetSize(540, 360)
    importWin:SetClampedToScreen(true)
    ApplyFrameSkin(importWin)
    PrepareFloatingPopupWindow(importWin)

    local title = importWin:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    title:SetPoint("TOPLEFT", 12, -10)
    title:SetText("Lid Import")
    importWin.title = title

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

    local nameLabel = importWin:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    nameLabel:SetPoint("TOPLEFT", 12, -40)
    nameLabel:SetText("New Profile Name:")
    importWin.nameLabel = nameLabel

    local nameEdit = CreateFrame("EditBox", nil, importWin, "InputBoxTemplate")
    nameEdit:SetSize(220, 20)
    nameEdit:SetPoint("TOPLEFT", 130, -36)
    nameEdit:SetAutoFocus(false)
    importWin.nameEdit = nameEdit

    local boxFrame, boxEdit = CreateScrollEditBox(importWin, 510, 220)
    boxFrame:SetPoint("TOPLEFT", 12, -70)
    importWin.boxFrame = boxFrame
    importWin.boxEdit = boxEdit
    if boxEdit.ClearAllPoints then
      boxEdit:ClearAllPoints()
      boxEdit:SetPoint("TOPLEFT", 0, 0)
    end
    boxEdit:SetSize(1, 1)
    if boxEdit.SetAlpha then
      boxEdit:SetAlpha(0.01)
    end
    if boxEdit.SetTextColor then
      boxEdit:SetTextColor(1.00, 1.00, 1.00, 0.00)
    end
    local previewParent = importWin.boxFrame and importWin.boxFrame.contentFrame or boxEdit
    local previewText = previewParent:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    previewText:SetPoint("TOPLEFT", 4, -4)
    previewText:SetWidth(458)
    previewText:SetJustifyH("LEFT")
    previewText:SetJustifyV("TOP")
    if previewText.SetNonSpaceWrap then
      previewText:SetNonSpaceWrap(true)
    end
    if previewText.SetWordWrap then
      previewText:SetWordWrap(true)
    end
    previewText:SetSpacing(2)
    previewText:SetTextColor(1.00, 1.00, 1.00, 1.00)
    previewText:SetText("")
    boxEdit.__lidPreviewText = previewText

    local focusMarker = previewParent:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    focusMarker:SetPoint("TOPLEFT", 4, -4)
    focusMarker:SetText("|cffff5a5a>|r")
    focusMarker:Hide()
    importWin.focusMarker = focusMarker

    boxFrame:EnableMouse(true)
    boxFrame:SetScript("OnMouseDown", function()
      if importWin and importWin.boxEdit then
        importWin.boxEdit:SetFocus()
      end
    end)

    local captureStatus = importWin:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    captureStatus:SetPoint("BOTTOMLEFT", 16, 42)
    captureStatus:SetPoint("BOTTOMRIGHT", -16, 42)
    captureStatus:SetJustifyH("LEFT")
    captureStatus:SetText("Press Ctrl+V here or type manually.")
    importWin.captureStatus = captureStatus

    local function SetImportInputFocusState(hasFocus)
      if importWin.boxFrame and importWin.boxFrame.SetBackdropBorderColor then
        if hasFocus then
          importWin.boxFrame:SetBackdropBorderColor(0.95, 0.46, 0.50, 0.98)
        else
          importWin.boxFrame:SetBackdropBorderColor(0, 0, 0, 0.9)
        end
      end
      if importWin.focusMarker then
        importWin.focusMarker:SetShown(hasFocus and tostring(importWin.__lidImportRawText or "") == "")
      end
      if importWin.captureStatus and tostring(importWin.__lidImportRawText or "") == "" then
        if hasFocus then
          importWin.captureStatus:SetText("Input active: press Ctrl+V or type manually.")
        else
          importWin.captureStatus:SetText("Press Ctrl+V here or type manually.")
        end
      end
    end
    importWin.SetImportInputFocusState = SetImportInputFocusState

    local pastePlaceholder = CreateFrame("Button", nil, boxFrame)
    pastePlaceholder:SetPoint("TOPLEFT", 2, -2)
    pastePlaceholder:SetPoint("BOTTOMRIGHT", -2, 2)
    pastePlaceholder:SetNormalTexture("Interface/Buttons/WHITE8x8")
    pastePlaceholder:GetNormalTexture():SetVertexColor(0, 0, 0, 0)
    pastePlaceholder:SetScript("OnClick", function()
      if importWin and importWin.boxEdit then
        importWin.boxEdit:SetFocus()
      end
    end)
    local placeholderText = pastePlaceholder:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
    placeholderText:SetPoint("TOPLEFT", 4, -2)
    placeholderText:SetJustifyH("LEFT")
    placeholderText:SetText("Click here and insert your string")
    pastePlaceholder.text = placeholderText
    importWin.pastePlaceholder = pastePlaceholder

    local function UpdateImportPlaceholder()
      if not importWin or not importWin.pastePlaceholder or not importWin.boxEdit then
        return
      end
      local text = importWin.__lidImportRawText or importWin.boxEdit:GetText() or ""
      local hasText = text ~= ""
      local focused = importWin.boxEdit:HasFocus() and true or false
      importWin.pastePlaceholder:SetShown((not hasText) and (not focused))
      if importWin.focusMarker then
        importWin.focusMarker:SetShown((not hasText) and focused)
      end
    end
    importWin.UpdateImportPlaceholder = UpdateImportPlaceholder
    boxEdit:HookScript("OnTextChanged", UpdateImportPlaceholder)
    boxEdit:HookScript("OnEditFocusGained", UpdateImportPlaceholder)
    boxEdit:HookScript("OnEditFocusLost", UpdateImportPlaceholder)
    boxEdit:HookScript("OnEditFocusGained", function()
      if importWin.SetImportInputFocusState then
        importWin:SetImportInputFocusState(true)
      end
    end)
    boxEdit:HookScript("OnEditFocusLost", function()
      if importWin.SetImportInputFocusState then
        importWin:SetImportInputFocusState(false)
      end
    end)

    local function RefreshImportCapturePreview()
      if not importWin or not importWin.boxEdit then
        return
      end
      local rawText = tostring(importWin.__lidImportRawText or "")
      if importWin.boxEdit.__lidPreviewText then
        local previewText = rawText
        local previewLimit = math.max(0, math.floor(tonumber(importWin.__previewLimit) or 0))
        if previewLimit > 0 and #rawText > previewLimit then
          previewText = rawText:sub(1, previewLimit)
            .. string.format("\n\n[Preview limited: %d characters captured]", #rawText)
        end
        importWin.boxEdit.__lidPreviewText:SetText(previewText)
      end
      importWin.boxEdit:SetText("")
      if importWin.boxEdit.SetCursorPosition then
        importWin.boxEdit:SetCursorPosition(0)
      end
      importWin.boxEdit.__lidCapturedPaste = rawText
      if importWin.captureStatus then
        if rawText == "" then
          if importWin.boxEdit:HasFocus() then
            importWin.captureStatus:SetText("Input active: press Ctrl+V or type manually.")
          else
            importWin.captureStatus:SetText("Press Ctrl+V here or type manually.")
          end
        else
          importWin.captureStatus:SetText(string.format("Captured %d characters.", #rawText))
        end
      end
      if importWin.boxFrame and importWin.boxFrame.UpdateMetrics then
        importWin.boxFrame:UpdateMetrics()
      end
      if importWin.boxFrame and importWin.boxFrame.scrollFrame and importWin.boxFrame.scrollFrame.SetVerticalScroll then
        importWin.boxFrame.scrollFrame:SetVerticalScroll(0)
      end
      if importWin.UpdateImportPlaceholder then
        importWin:UpdateImportPlaceholder()
      end
    end

    local function FlushBufferedImportChars()
      if not importWin or not importWin.boxEdit then
        return
      end
      importWin.boxEdit:SetScript("OnUpdate", nil)
      importWin.boxEdit.__lidImportFlushScheduled = nil
      local pending = importWin.__lidImportPending or {}
      local chunk = table.concat(pending)
      if type(wipe) == "function" then
        wipe(pending)
      else
        importWin.__lidImportPending = {}
      end
      if chunk ~= "" then
        importWin.__lidImportRawText = tostring(importWin.__lidImportRawText or "") .. chunk
        RefreshImportCapturePreview()
      end
    end

    boxEdit:SetScript("OnChar", function(self, char)
      importWin.__lidImportPending = importWin.__lidImportPending or {}
      local pending = importWin.__lidImportPending
      pending[#pending + 1] = char
      if self.__lidImportFlushScheduled then
        return
      end
      self.__lidImportFlushScheduled = true
      self:SetScript("OnUpdate", FlushBufferedImportChars)
    end)

    boxEdit:SetScript("OnKeyDown", function(self, key)
      if key == "BACKSPACE" then
        local rawText = tostring(importWin.__lidImportRawText or "")
        if rawText ~= "" then
          importWin.__lidImportRawText = rawText:sub(1, #rawText - 1)
          RefreshImportCapturePreview()
        end
      elseif key == "ENTER" then
        importWin.__lidImportRawText = tostring(importWin.__lidImportRawText or "") .. "\n"
        RefreshImportCapturePreview()
      end
    end)
    importWin.RefreshImportCapturePreview = RefreshImportCapturePreview

    local importBtn = CreateFrame("Button", nil, importWin, "UIPanelButtonTemplate")
    importBtn:SetSize(110, 22)
    importBtn:SetPoint("BOTTOMRIGHT", -12, 12)
    importBtn:SetText("Import")
    importWin.importBtn = importBtn

    local cancelBtn = CreateFrame("Button", nil, importWin, "UIPanelButtonTemplate")
    cancelBtn:SetSize(110, 22)
    cancelBtn:SetPoint("RIGHT", importBtn, "LEFT", -8, 0)
    cancelBtn:SetText("Cancel")
    cancelBtn:SetScript("OnClick", function()
      importWin:Hide()
    end)

    importBtn:SetScript("OnClick", function()
      local newName = (importWin.nameEdit:GetText() or ""):gsub("^%s+", ""):gsub("%s+$", "")
      local pasted = importWin.boxEdit.__lidCapturedPaste or importWin.boxEdit:GetText() or ""
      if importWin.__requireName ~= false and newName == "" then
        Print("Import: please enter a profile name.")
        return
      end
      if type(importWin.__onImport) == "function" then
        importWin.__onImport(newName, pasted)
      end
      importWin:Hide()
    end)
  end

  importWin.__onImport = onImport
  importWin.__requireName = opts.requireName ~= false
  importWin.__previewLimit = math.max(0, math.floor(tonumber(opts.previewLimit) or 0))
  if importWin.title then
    importWin.title:SetText(tostring(opts.title or "Lid Import"))
  end
  if importWin.nameLabel then
    importWin.nameLabel:SetText(tostring(opts.nameLabel or "New Profile Name:"))
    importWin.nameLabel:SetShown(importWin.__requireName)
  end
  if importWin.nameEdit then
    importWin.nameEdit:SetShown(importWin.__requireName)
  end
  if importWin.importBtn then
    importWin.importBtn:SetText(tostring(opts.buttonText or "Import"))
  end
  if importWin.pastePlaceholder and importWin.pastePlaceholder.text then
    importWin.pastePlaceholder.text:SetText(tostring(opts.placeholder or "Click here and insert your string"))
  end
  if exportWin and exportWin:IsShown() then
    exportWin:Hide()
  end

  importWin.nameEdit:SetText("")
  importWin.boxEdit:SetText("")
  importWin.__lidImportRawText = ""
  importWin.__lidImportPending = {}
  importWin.boxEdit.__lidCapturedPaste = nil
  local boxFrame = importWin.boxEdit and importWin.boxEdit:GetParent() or nil
  if boxFrame then
    boxFrame:ClearAllPoints()
    if importWin.__requireName then
      boxFrame:SetPoint("TOPLEFT", 12, -70)
    else
      boxFrame:SetPoint("TOPLEFT", 12, -40)
    end
  end
  if importWin.RefreshImportCapturePreview then
    importWin:RefreshImportCapturePreview()
  end
  if importWin.SetImportInputFocusState then
    importWin:SetImportInputFocusState(false)
  end

  RaiseFloatingPopupWindow(importWin)
  if not importWin.__lidPlaced then
    importWin.__lidPlaced = true
    importWin:ClearAllPoints()
    importWin:SetPoint("CENTER", UIParent, "CENTER", 220, 0)
  end
  importWin:Show()
  if importWin.boxEdit then
    importWin.boxEdit:SetFocus()
    if importWin.boxEdit.HighlightText then
      importWin.boxEdit:HighlightText(0, 0)
    end
    if importWin.boxEdit.SetCursorPosition then
      importWin.boxEdit:SetCursorPosition(0)
    end
  end
  if importWin.SetImportInputFocusState then
    importWin:SetImportInputFocusState(true)
  end
end

local function ShowSettingsImportWindow(onImport, opts)
  opts = type(opts) == "table" and opts or {}
  if not settingsImportWin then
    settingsImportWin = CreateFrame("Frame", "LIDCOUNCIL_SettingsImportWindow", UIParent, "BackdropTemplate")
    settingsImportWin:SetSize(620, 420)
    settingsImportWin:SetClampedToScreen(true)
    ApplyFrameSkin(settingsImportWin)
    PrepareFloatingPopupWindow(settingsImportWin)

    local title = settingsImportWin:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    title:SetPoint("TOPLEFT", 12, -10)
    title:SetText("Import Settings")
    settingsImportWin.title = title

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

    local hint = settingsImportWin:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    hint:SetPoint("TOPLEFT", 16, -40)
    hint:SetPoint("TOPRIGHT", -16, -40)
    hint:SetJustifyH("LEFT")
    hint:SetText("Click the box below, then paste or type your settings string.")
    settingsImportWin.hint = hint

    local box = CreateFrame("Frame", nil, settingsImportWin, "BackdropTemplate")
    box:SetPoint("TOPLEFT", 16, -64)
    box:SetPoint("BOTTOMRIGHT", -16, 48)
    box:SetBackdrop({
      bgFile = "Interface/Buttons/WHITE8x8",
      edgeFile = "Interface/Buttons/WHITE8x8",
      tile = false,
      edgeSize = 1,
      insets = { left = 1, right = 1, top = 1, bottom = 1 },
    })
    box:SetBackdropColor(0.05, 0.05, 0.07, 0.85)
    box:SetBackdropBorderColor(0, 0, 0, 0.9)
    settingsImportWin.box = box

    local scroll = CreateFrame("ScrollFrame", nil, box, "UIPanelScrollFrameTemplate")
    scroll:SetPoint("TOPLEFT", 6, -6)
    scroll:SetPoint("BOTTOMRIGHT", -28, 6)
    settingsImportWin.scroll = scroll

    local content = CreateFrame("Frame", nil, scroll)
    content:SetSize(1, 1)
    scroll:SetScrollChild(content)
    settingsImportWin.content = content

    local preview = content:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    preview:SetPoint("TOPLEFT", 0, 0)
    preview:SetWidth(540)
    preview:SetJustifyH("LEFT")
    preview:SetJustifyV("TOP")
    if preview.SetWordWrap then
      preview:SetWordWrap(true)
    end
    if preview.SetNonSpaceWrap then
      preview:SetNonSpaceWrap(true)
    end
    preview:SetSpacing(2)
    preview:SetTextColor(1.00, 1.00, 1.00, 1.00)
    preview:SetText("")
    settingsImportWin.preview = preview

    local placeholder = box:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
    placeholder:SetPoint("TOPLEFT", 10, -10)
    placeholder:SetPoint("TOPRIGHT", -34, -10)
    placeholder:SetJustifyH("LEFT")
    placeholder:SetText("Click here and insert your string")
    settingsImportWin.placeholder = placeholder

    local caret = box:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    caret:SetPoint("TOPLEFT", 10, -10)
    caret:SetText("|cffff5a5a>|r")
    caret:Hide()
    settingsImportWin.caret = caret

    local status = settingsImportWin:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    status:SetPoint("BOTTOMLEFT", 16, 28)
    status:SetPoint("BOTTOMRIGHT", -16, 28)
    status:SetJustifyH("LEFT")
    status:SetText("")
    settingsImportWin.status = status

    local hiddenEdit = CreateFrame("EditBox", nil, settingsImportWin, "InputBoxTemplate")
    hiddenEdit:SetSize(1, 1)
    hiddenEdit:SetPoint("TOPLEFT", settingsImportWin, "BOTTOMLEFT", 0, -20)
    hiddenEdit:SetAlpha(0.01)
    hiddenEdit:SetAutoFocus(false)
    hiddenEdit:SetMultiLine(true)
    hiddenEdit:EnableKeyboard(true)
    hiddenEdit:EnableMouse(true)
    if hiddenEdit.SetMaxLetters then
      hiddenEdit:SetMaxLetters(0)
    end
    settingsImportWin.hiddenEdit = hiddenEdit

    local function UpdateVisibleState()
      local rawText = tostring(settingsImportWin.__rawText or "")
      local focused = hiddenEdit:HasFocus() and true or false
      preview:SetText(rawText)
      local previewHeight = math.max(24, math.ceil(tonumber(preview:GetStringHeight()) or 0) + 4)
      content:SetWidth(math.max(1, scroll:GetWidth() - 6))
      content:SetHeight(previewHeight)
      preview:SetWidth(math.max(1, scroll:GetWidth() - 6))
      scroll:UpdateScrollChildRect()
      scroll:SetVerticalScroll(0)
      placeholder:SetShown((rawText == "") and (not focused))
      caret:SetShown((rawText == "") and focused)
      if rawText == "" then
        status:SetText(focused and "Input active: press Ctrl+V or type manually." or "Click the box above, then paste or type your settings string.")
      else
        status:SetText(string.format("Captured %d characters.", #rawText))
      end
      if focused then
        box:SetBackdropBorderColor(0.95, 0.46, 0.50, 0.98)
      else
        box:SetBackdropBorderColor(0, 0, 0, 0.9)
      end
    end
    settingsImportWin.UpdateVisibleState = UpdateVisibleState

    box:EnableMouse(true)
    box:SetScript("OnMouseDown", function()
      hiddenEdit:SetFocus()
      if settingsImportWin.UpdateVisibleState then
        settingsImportWin:UpdateVisibleState()
      end
    end)

    hiddenEdit:SetScript("OnEscapePressed", function(self)
      self:ClearFocus()
      if settingsImportWin.UpdateVisibleState then
        settingsImportWin:UpdateVisibleState()
      end
    end)
    hiddenEdit:SetScript("OnEditFocusGained", function()
      if settingsImportWin.UpdateVisibleState then
        settingsImportWin:UpdateVisibleState()
      end
    end)
    hiddenEdit:SetScript("OnEditFocusLost", function()
      if settingsImportWin.UpdateVisibleState then
        settingsImportWin:UpdateVisibleState()
      end
    end)
    hiddenEdit:SetScript("OnChar", function(_, char)
      settingsImportWin.__rawText = tostring(settingsImportWin.__rawText or "") .. tostring(char or "")
      if settingsImportWin.UpdateVisibleState then
        settingsImportWin:UpdateVisibleState()
      end
    end)
    hiddenEdit:SetScript("OnKeyDown", function(_, key)
      local rawText = tostring(settingsImportWin.__rawText or "")
      if key == "BACKSPACE" then
        if rawText ~= "" then
          settingsImportWin.__rawText = rawText:sub(1, #rawText - 1)
          if settingsImportWin.UpdateVisibleState then
            settingsImportWin:UpdateVisibleState()
          end
        end
      elseif key == "ENTER" then
        settingsImportWin.__rawText = rawText .. "\n"
        if settingsImportWin.UpdateVisibleState then
          settingsImportWin:UpdateVisibleState()
        end
      end
    end)

    local importBtn = CreateFrame("Button", nil, settingsImportWin, "UIPanelButtonTemplate")
    importBtn:SetSize(110, 22)
    importBtn:SetPoint("BOTTOMRIGHT", -12, 12)
    importBtn:SetText("Import")
    importBtn:SetScript("OnClick", function()
      if type(settingsImportWin.__onImport) == "function" then
        settingsImportWin.__onImport("", tostring(settingsImportWin.__rawText or ""))
      end
      settingsImportWin:Hide()
    end)
    settingsImportWin.importBtn = importBtn

    local cancelBtn = CreateFrame("Button", nil, settingsImportWin, "UIPanelButtonTemplate")
    cancelBtn:SetSize(110, 22)
    cancelBtn:SetPoint("RIGHT", importBtn, "LEFT", -8, 0)
    cancelBtn:SetText("Cancel")
    cancelBtn:SetScript("OnClick", function()
      settingsImportWin:Hide()
    end)
  end

  settingsImportWin.__onImport = onImport
  if settingsImportWin.title then
    settingsImportWin.title:SetText(tostring(opts.title or "Import Settings"))
  end
  if settingsImportWin.placeholder then
    settingsImportWin.placeholder:SetText(tostring(opts.placeholder or "Click here and insert your string"))
  end
  if settingsImportWin.importBtn then
    settingsImportWin.importBtn:SetText(tostring(opts.buttonText or "Import"))
  end
  settingsImportWin.__rawText = ""
  if settingsImportWin.UpdateVisibleState then
    settingsImportWin:UpdateVisibleState()
  end

  RaiseFloatingPopupWindow(settingsImportWin)
  if not settingsImportWin.__lidPlaced then
    settingsImportWin.__lidPlaced = true
    settingsImportWin:ClearAllPoints()
    settingsImportWin:SetPoint("CENTER", UIParent, "CENTER", 220, 0)
  end
  settingsImportWin:Show()
end

PublishApi("LIDCOUNCIL_ShowErrorLogWindow", ShowErrorLogWindow)
PublishApi("LIDCOUNCIL_ShowSilentLogWindow", ShowSilentLogWindow)
PublishApi("LIDCOUNCIL_ShowExportWindow", ShowExportWindow)
PublishApi("LIDCOUNCIL_ShowCopyTextWindow", ShowCopyTextWindow)
PublishApi("LIDCOUNCIL_ShowImportWindow", ShowImportWindow)
PublishApi("LIDCOUNCIL_ShowSettingsImportWindow", ShowSettingsImportWindow)
