local addonName, ns = ...

local cache = {}
local W = ns.Widgets
local C = ns.COLORS

-- Styled dropdown colors (match Widgets.lua)
local DARK_BG_R, DARK_BG_G, DARK_BG_B = 0.08, 0.08, 0.08
local BTN_BLUE_R, BTN_BLUE_G, BTN_BLUE_B = 0.004, 0.557, 0.906
local BTN_BLUE_R, BTN_BLUE_G, BTN_BLUE_B = 0.004, 0.557, 0.906

-- Class colour (lazy, resolved after PLAYER_LOGIN)
local _CCR, _CCG, _CCB
local function CC3()
    if not _CCR then
        if ns and ns.GetClassColor then
            _CCR, _CCG, _CCB = ns.GetClassColor()
        else
            local _, cf = UnitClass("player")
            local c = cf and RAID_CLASS_COLORS and RAID_CLASS_COLORS[cf]
            if c then _CCR, _CCG, _CCB = c.r, c.g, c.b
            else      _CCR, _CCG, _CCB = 168/255, 85/255, 247/255 end
        end
    end
    return _CCR, _CCG, _CCB
end

-- Dynamic dropdown for profile selection (with frame pooling)
local function CreateDynamicDropdown(parent, opts)
    opts = opts or {}
    local width = opts.width or 160
    local height = 22
    local itemHeight = 20

    local f = CreateFrame("Frame", nil, parent)
    f:SetSize(width, height)

    -- Dropdown button
    local btn = CreateFrame("Button", nil, f, "BackdropTemplate")
    btn:SetSize(width, height)
    btn:SetPoint("TOPLEFT", 0, 0)
    btn:SetBackdrop({
        bgFile = [[Interface\Buttons\WHITE8x8]],
        edgeFile = [[Interface\Buttons\WHITE8x8]],
        edgeSize = 1,
    })
    btn:SetBackdropColor(DARK_BG_R, DARK_BG_G, DARK_BG_B, 0.95)
    btn:SetBackdropBorderColor(BTN_BLUE_R, BTN_BLUE_G, BTN_BLUE_B, 0.7)
    f.button = btn

    -- Selected text
    local text = btn:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    text:SetPoint("LEFT", 8, 0)
    text:SetPoint("RIGHT", -20, 0)
    text:SetJustifyH("LEFT")
    text:SetTextColor(1, 1, 1, 1)
    text:SetText(opts.placeholder or "Select...")
    btn.text = text
    f.text = text

    -- Arrow texture
    local arrow = btn:CreateTexture(nil, "OVERLAY")
    arrow:SetSize(12, 12)
    arrow:SetPoint("RIGHT", -4, 0)
    arrow:SetTexture([[Interface\Buttons\UI-ScrollBar-ScrollDownButton-Up]])
    arrow:SetTexCoord(0.25, 0.75, 0.25, 0.75)
    local _r, _g, _b = CC3()
    arrow:SetVertexColor(_r, _g, _b, 1)

    -- Dropdown menu frame
    local menu = CreateFrame("Frame", nil, btn, "BackdropTemplate")
    menu:SetPoint("TOPLEFT", btn, "BOTTOMLEFT", 0, -2)
    menu:SetWidth(width)
    menu:SetBackdrop({
        bgFile = [[Interface\Buttons\WHITE8x8]],
        edgeFile = [[Interface\Buttons\WHITE8x8]],
        edgeSize = 1,
    })
    menu:SetBackdropColor(DARK_BG_R, DARK_BG_G, DARK_BG_B, 0.98)
    menu:SetBackdropBorderColor(BTN_BLUE_R, BTN_BLUE_G, BTN_BLUE_B, 0.7)
    menu:SetFrameStrata("DIALOG")
    menu:SetFrameLevel(100)
    menu:Hide()
    f.menu = menu

    f.menuOpen = false
    f.itemPool = {}
    f.activeItems = {}
    f.selectedValue = nil

    -- Pre-create empty state frame (reused)
    local emptyItem = CreateFrame("Frame", nil, menu)
    emptyItem:SetSize(width - 2, itemHeight)
    emptyItem:SetPoint("TOPLEFT", 1, -1)
    local emptyText = emptyItem:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
    emptyText:SetPoint("LEFT", 8, 0)
    emptyText:SetText(opts.emptyText or "(None)")
    emptyItem:Hide()
    f.emptyItem = emptyItem

    function f:SetText(str)
        text:SetText(str)
    end

    function f:GetSelectedValue()
        return f.selectedValue
    end

    function f:SetSelectedValue(val)
        f.selectedValue = val
    end

    -- Get or create pooled menu item
    local function GetPooledItem()
        for _, item in ipairs(f.itemPool) do
            if not item.inUse then
                item.inUse = true
                item:Show()
                return item
            end
        end

        -- Create new item
        local item = CreateFrame("Button", nil, menu, "BackdropTemplate")
        item:SetSize(width - 2, itemHeight)
        item:SetBackdrop({ bgFile = [[Interface\Buttons\WHITE8x8]] })
        item:SetBackdropColor(0, 0, 0, 0)

        item.label = item:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        item.label:SetPoint("LEFT", 8, 0)
        item.label:SetPoint("RIGHT", -8, 0)
        item.label:SetJustifyH("LEFT")
        item.label:SetTextColor(1, 1, 1, 1)

        item:SetScript("OnEnter", function(self)
            local _r, _g, _b = CC3()
            self:SetBackdropColor(_r, _g, _b, 0.3)
        end)
        item:SetScript("OnLeave", function(self)
            self:SetBackdropColor(0, 0, 0, 0)
        end)

        f.itemPool[#f.itemPool + 1] = item
        item.inUse = true
        return item
    end

    function f:Refresh(options)
        -- Return all items to pool
        for _, item in ipairs(f.activeItems) do
            item.inUse = false
            item:Hide()
        end
        f.activeItems = {}

        if #options == 0 then
            f.emptyItem:Show()
            menu:SetHeight(itemHeight + 2)
        else
            f.emptyItem:Hide()

            for i, opt in ipairs(options) do
                local item = GetPooledItem()
                item:ClearAllPoints()
                item:SetPoint("TOPLEFT", 1, -1 - (i - 1) * itemHeight)
                item.label:SetText(opt.text)
                item.optValue = opt.value
                item.optText = opt.text

                item:SetScript("OnClick", function(self)
                    f.selectedValue = self.optValue
                    text:SetText(self.optText)
                    menu:Hide()
                    if opts.onSelect then opts.onSelect(self.optValue, self.optText) end
                end)

                f.activeItems[i] = item
            end

            menu:SetHeight(#options * itemHeight + 2)
        end
    end

    -- Toggle menu
    btn:SetScript("OnClick", function()
        if f.menuOpen then
            menu:Hide()
        else
            menu:Show()
            f.menuOpen = true
            local _r, _g, _b = CC3()
            btn:SetBackdropBorderColor(_r, _g, _b, 0.9)
        end
    end)

    btn:SetScript("OnEnter", function(self)
        if not f.menuOpen then
            local _r, _g, _b = CC3()
            self:SetBackdropBorderColor(_r, _g, _b, 0.9)
        end
    end)
    btn:SetScript("OnLeave", function(self)
        if not f.menuOpen then
            self:SetBackdropBorderColor(BTN_BLUE_R, BTN_BLUE_G, BTN_BLUE_B, 0.7)
        end
    end)

    -- OnUpdate only runs when menu is open
    menu:SetScript("OnShow", function()
        f:SetScript("OnUpdate", function()
            if not menu:IsMouseOver() and not btn:IsMouseOver() then
                if IsMouseButtonDown("LeftButton") or IsMouseButtonDown("RightButton") then
                    menu:Hide()
                end
            end
        end)
    end)

    menu:SetScript("OnHide", function()
        f:SetScript("OnUpdate", nil)
        f.menuOpen = false
        btn:SetBackdropBorderColor(BTN_BLUE_R, BTN_BLUE_G, BTN_BLUE_B, 0.7)
    end)

    return f
end

-- Static popup for profile name input
StaticPopupDialogs["BRIGHTQOL_PROFILE_NAME"] = {
    text = "%s",
    button1 = "OK",
    button2 = "Cancel",
    hasEditBox = true,
    OnShow = function(self)
        local editBox = self.editBox or self.EditBox
        if editBox then
            editBox:SetText(self.data and self.data.default or "")
            editBox:HighlightText()
        end
    end,
    OnAccept = function(self)
        local editBox = self.editBox or self.EditBox
        local name = editBox and strtrim(editBox:GetText()) or ""
        if name ~= "" and self.data and self.data.callback then
            self.data.callback(name)
        end
    end,
    EditBoxOnEnterPressed = function(self)
        local parent = self:GetParent()
        local name = strtrim(self:GetText())
        if name ~= "" and parent.data and parent.data.callback then
            parent.data.callback(name)
        end
        parent:Hide()
    end,
    timeout = 0,
    whileDead = true,
    hideOnEscape = true,
    preferredIndex = 3,
}

StaticPopupDialogs["BRIGHTQOL_PROFILE_CONFIRM"] = {
    text = "%s",
    button1 = "Yes",
    button2 = "No",
    OnAccept = function(self)
        if self.data and self.data.callback then
            self.data.callback()
        end
    end,
    timeout = 0,
    whileDead = true,
    hideOnEscape = true,
    preferredIndex = 3,
}

function ns:InitImportExport()
    local p = ns.MainFrame.Content

    W:CachedPanel(cache, "frame", p, function(f)
        local _, sc = W:CreateScrollFrame(f, 1200)

        W:CreatePageHeader(sc,
            W.Colorize("PRO", C.BLUE) .. W.Colorize("FILES", C.ORANGE),
            W.Colorize("Share settings between characters or with other players", C.BLUE),
            { subtitleFont = "GameFontHighlightSmall", separator = false })

        -- Profile Management Section
        W:CreateSectionHeader(sc, "Profile Management", -80)

        local profileStatus = sc:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        profileStatus:SetPoint("TOPLEFT", 35, -115)
        profileStatus:SetText("")

        local function UpdateProfileStatus()
            local active = ns.SettingsIO:GetActiveProfile()
            local count = #ns.SettingsIO:GetProfileList()
            profileStatus:SetText("|cff44ff44Active: " .. active .. "|r  (" .. count .. " saved)")
        end

        -- Profile dropdown
        local profileDropdown = CreateDynamicDropdown(sc, {
            width = 160,
            placeholder = "Select Profile",
            emptyText = "(No saved profiles)",
            onSelect = function(name)
                local ok, err = ns.SettingsIO:LoadProfile(name)
                if ok then
                    UpdateProfileStatus()
                    profileStatus:SetText("|cff44ff44Loaded: " .. name .. "|r")
                else
                    profileStatus:SetText("|cffff4444" .. (err or "Failed to load") .. "|r")
                end
            end
        })
        profileDropdown:SetPoint("TOPLEFT", 35, -135)

        local function RefreshProfileDropdown()
            local profiles = ns.SettingsIO:GetProfileList()
            local options = {}
            for _, name in ipairs(profiles) do
                options[#options + 1] = { text = name, value = name }
            end
            profileDropdown:Refresh(options)
            profileDropdown:SetText(ns.SettingsIO:GetActiveProfile())
            profileDropdown:SetSelectedValue(ns.SettingsIO:GetActiveProfile())
        end

        -- Forward declarations for spec profile dropdowns
        local specDropdowns = {}
        local RefreshSpecDropdowns

        -- Save button
        local saveBtn = W:CreateButton(sc, { text = "Save", width = 60, height = 24 })
        saveBtn:SetPoint("LEFT", profileDropdown, "RIGHT", 8, 0)
        saveBtn:SetScript("OnClick", function()
            local dialog = StaticPopup_Show("BRIGHTQOL_PROFILE_NAME", "Save current settings as profile:")
            if dialog then
                dialog.data = {
                    default = ns.SettingsIO:GetActiveProfile(),
                    callback = function(name)
                        ns.SettingsIO:SaveProfile(name)
                        RefreshProfileDropdown()
                        if RefreshSpecDropdowns then RefreshSpecDropdowns() end
                        UpdateProfileStatus()
                        profileStatus:SetText("|cff44ff44Saved: " .. name .. "|r")
                    end
                }
            end
        end)

        -- Rename button
        local renameBtn = W:CreateButton(sc, { text = "Rename", width = 70, height = 24 })
        renameBtn:SetPoint("LEFT", saveBtn, "RIGHT", 4, 0)
        renameBtn:SetScript("OnClick", function()
            local current = ns.SettingsIO:GetActiveProfile()
            if not BrightQoL.profiles or not BrightQoL.profiles[current] then
                profileStatus:SetText("|cffff4444Save profile first|r")
                return
            end
            local dialog = StaticPopup_Show("BRIGHTQOL_PROFILE_NAME", "Rename profile '" .. current .. "' to:")
            if dialog then
                dialog.data = {
                    default = current,
                    callback = function(newName)
                        if ns.SettingsIO:RenameProfile(current, newName) then
                            RefreshProfileDropdown()
                            if RefreshSpecDropdowns then RefreshSpecDropdowns() end
                            UpdateProfileStatus()
                            profileStatus:SetText("|cff44ff44Renamed to: " .. newName .. "|r")
                        else
                            profileStatus:SetText("|cffff4444Name already exists|r")
                        end
                    end
                }
            end
        end)

        -- Delete button
        local deleteBtn = W:CreateButton(sc, { text = "Delete", width = 60, height = 24 })
        deleteBtn:SetPoint("LEFT", renameBtn, "RIGHT", 4, 0)
        deleteBtn:SetScript("OnClick", function()
            local current = ns.SettingsIO:GetActiveProfile()
            if not BrightQoL.profiles or not BrightQoL.profiles[current] then
                profileStatus:SetText("|cffff4444No profile to delete|r")
                return
            end
            local dialog = StaticPopup_Show("BRIGHTQOL_PROFILE_CONFIRM", "Delete profile '" .. current .. "'?")
            if dialog then
                dialog.data = {
                    callback = function()
                        ns.SettingsIO:DeleteProfile(current)
                        RefreshProfileDropdown()
                        if RefreshSpecDropdowns then RefreshSpecDropdowns() end
                        UpdateProfileStatus()
                        profileStatus:SetText("|cff44ff44Deleted|r")
                    end
                }
            end
        end)

        -- New profile button (creates profile with default settings)
        local newBtn = W:CreateButton(sc, { text = "New", width = 60, height = 24 })
        newBtn:SetPoint("LEFT", deleteBtn, "RIGHT", 4, 0)
        newBtn:SetScript("OnClick", function()
            local dialog = StaticPopup_Show("BRIGHTQOL_PROFILE_NAME", "Create new profile with default settings:")
            if dialog then
                dialog.data = {
                    default = "",
                    callback = function(name)
                        if BrightQoL.profiles and BrightQoL.profiles[name] then
                            profileStatus:SetText("|cffff4444Name already exists|r")
                            return
                        end
                        ns.SettingsIO:CreateDefaultProfile(name)
                        RefreshProfileDropdown()
                        if RefreshSpecDropdowns then RefreshSpecDropdowns() end
                        UpdateProfileStatus()
                        profileStatus:SetText("|cff44ff44Created: " .. name .. "|r")
                    end
                }
            end
        end)

        -- Copy profile section
        W:CreateSectionHeader(sc, "Copy Profile", -180)

        local copyStatus = sc:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        copyStatus:SetPoint("TOPLEFT", 35, -245)
        copyStatus:SetText("")

        local selectedChar = nil

        local charProfileDropdown = CreateDynamicDropdown(sc, {
            width = 160,
            placeholder = "Select Profile",
            emptyText = "(Select character first)",
        })

        local charDropdown = CreateDynamicDropdown(sc, {
            width = 160,
            placeholder = "Select Character",
            emptyText = "(No saved profiles)",
            onSelect = function(charKey)
                selectedChar = charKey
                -- Refresh the profile dropdown for selected character
                local profiles = ns.SettingsIO:GetCharacterProfiles(charKey)
                local options = {}
                for _, name in ipairs(profiles) do
                    options[#options + 1] = { text = name, value = name }
                end
                charProfileDropdown:Refresh(options)
                charProfileDropdown:SetText("Select Profile")
                charProfileDropdown:SetSelectedValue(nil)
            end
        })
        charDropdown:SetPoint("TOPLEFT", 35, -218)
        charProfileDropdown:SetPoint("LEFT", charDropdown, "RIGHT", 8, 0)

        local function RefreshCharProfileDropdown()
            if not selectedChar then
                charProfileDropdown:Refresh({})
                charProfileDropdown:SetText("Select Profile")
                return
            end
            local profiles = ns.SettingsIO:GetCharacterProfiles(selectedChar)
            local options = {}
            for _, name in ipairs(profiles) do
                options[#options + 1] = { text = name, value = name }
            end
            charProfileDropdown:Refresh(options)
        end

        local function RefreshCharDropdown()
            local chars = ns.SettingsIO:GetOtherCharacters()
            local options = {}
            for _, charKey in ipairs(chars) do
                options[#options + 1] = { text = charKey, value = charKey }
            end
            charDropdown:Refresh(options)
            charDropdown:SetText("Select Character")
        end

        local copyBtn = W:CreateButton(sc, { text = "Copy", width = 60, height = 24 })
        copyBtn:SetPoint("LEFT", charProfileDropdown, "RIGHT", 8, 0)
        copyBtn:SetScript("OnClick", function()
            local charKey = charDropdown:GetSelectedValue()
            local profileName = charProfileDropdown:GetSelectedValue()
            if not charKey or not profileName then
                copyStatus:SetText("|cffff4444Select character and profile|r")
                return
            end
            local ok, err = ns.SettingsIO:CopyFromCharacter(charKey, profileName)
            if ok then
                copyStatus:SetText("|cff44ff44Copied from " .. charKey .. "|r")
                RefreshProfileDropdown()
                UpdateProfileStatus()
            else
                copyStatus:SetText("|cffff4444" .. (err or "Copy failed") .. "|r")
            end
        end)

        -- Spec Profile Swap Section
        W:CreateSectionHeader(sc, "Spec Profile Swap", -280)

        local specRows = {}

        RefreshSpecDropdowns = function()
            local profiles = ns.SettingsIO:GetProfileList()
            local options = {{ text = "(None)", value = "" }}
            for _, name in ipairs(profiles) do
                options[#options + 1] = { text = name, value = name }
            end
            for specIndex, dropdown in pairs(specDropdowns) do
                dropdown:Refresh(options)
                local specData = ns.SettingsIO:GetSpecProfileData(specIndex)
                if specData.profile and specData.profile ~= "" then
                    dropdown:SetText(specData.profile)
                    dropdown:SetSelectedValue(specData.profile)
                else
                    dropdown:SetText("(None)")
                    dropdown:SetSelectedValue("")
                end
            end
        end

        local function BuildSpecRows()
            local numSpecs = GetNumSpecializations()
            local yOffset = -315

            for i = 1, numSpecs do
                local specID, specName, _, specIcon = GetSpecializationInfo(i)
                if specName then
                    local specData = ns.SettingsIO:GetSpecProfileData(i)

                    -- Spec icon
                    local icon = sc:CreateTexture(nil, "ARTWORK")
                    icon:SetSize(20, 20)
                    icon:SetPoint("TOPLEFT", 35, yOffset)
                    icon:SetTexture(specIcon)
                    icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)

                    -- Enable checkbox
                    local specIndex = i
                    local cb = W:CreateCheckbox(sc, {
                        template = "interface",
                        checked = specData.enabled,
                        onChange = function(checked)
                            ns.SettingsIO:SetSpecProfileEnabled(specIndex, checked)
                        end
                    })
                    cb:SetPoint("LEFT", icon, "RIGHT", 6, 0)
                    cb.Text:SetText(specName)

                    -- Profile dropdown
                    local dropdown = CreateDynamicDropdown(sc, {
                        width = 140,
                        placeholder = "(None)",
                        emptyText = "(No profiles)",
                        onSelect = function(profileName)
                            ns.SettingsIO:SetSpecProfile(specIndex, profileName)
                        end
                    })
                    dropdown:SetPoint("LEFT", cb, "RIGHT", 100, 0)
                    specDropdowns[specIndex] = dropdown

                    specRows[i] = { icon = icon, checkbox = cb, dropdown = dropdown }
                    yOffset = yOffset - 45
                end
            end
        end

        -- Initialize dropdowns
        C_Timer.After(0.1, function()
            ns.SettingsIO:InitProfiles()
            RefreshProfileDropdown()
            RefreshCharDropdown()
            UpdateProfileStatus()
            BuildSpecRows()
            RefreshSpecDropdowns()
        end)

        -- Multi-line edit box helper
        local function MakeTextBox(parent, y, height, readOnly)
            local bg = CreateFrame("Frame", nil, parent, "BackdropTemplate")
            bg:SetSize(430, height)
            bg:SetPoint("TOPLEFT", 35, y)
            bg:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8x8",
                edgeFile = "Interface\\Buttons\\WHITE8x8", edgeSize = 1 })
            bg:SetBackdropColor(0.04, 0.04, 0.04, 1)
            bg:SetBackdropBorderColor(0, 0, 0, 1)

            local sf = CreateFrame("ScrollFrame", nil, bg, "UIPanelScrollFrameTemplate")
            sf:SetPoint("TOPLEFT", 6, -6); sf:SetPoint("BOTTOMRIGHT", -20, 6)

            local box = CreateFrame("EditBox", nil, sf)
            box:SetWidth(sf:GetWidth() or 400)
            box:SetFontObject("GameFontHighlightSmall")
            box:SetAutoFocus(false); box:SetMultiLine(true)
            box:SetMaxLetters(0)
            sf:SetScrollChild(box)

            -- Make entire background clickable to focus the edit box
            bg:EnableMouse(true)
            bg:SetScript("OnMouseDown", function() box:SetFocus() end)

            if readOnly then
                local storedText = ""
                box:SetScript("OnTextChanged", function(self, userInput)
                    if userInput then
                        self:SetText(storedText)
                        self:HighlightText()
                    else
                        storedText = self:GetText()
                    end
                end)
                box:SetScript("OnEditFocusGained", function(self) self:HighlightText() end)
                box:SetScript("OnCursorChanged", function(self) self:HighlightText() end)
                box:SetScript("OnEditFocusLost", function(self) self:SetText(""); self:HighlightText(0, 0) end)
            end
            box:SetScript("OnEscapePressed", function(self) self:ClearFocus() end)

            return box, bg
        end

        W:CreateSectionHeader(sc, "Export", -480)

        local exportBtn = W:CreateButton(sc, { text = "Export Settings", width = 130, height = 26 })
        exportBtn:SetPoint("TOPLEFT", 35, -515)

        local exportHint = sc:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
        exportHint:SetPoint("LEFT", exportBtn, "RIGHT", 10, 0)
        exportHint:SetText("Ctrl+A, Ctrl+C to copy")

        local exportBox = MakeTextBox(sc, -548, 80, true)

        exportBtn:SetScript("OnClick", function()
            if not ns.SettingsIO then return end
            local str = ns.SettingsIO:Export()
            exportBox:SetText(str)
            exportBox:SetFocus(); exportBox:HighlightText()
        end)

        W:CreateSectionHeader(sc, "Import", -645)

        local importBox = MakeTextBox(sc, -680, 80, false)

        local loadBtn = W:CreateButton(sc, { text = "Load", width = 80, height = 26 })
        loadBtn:SetPoint("TOPLEFT", 35, -768)

        local statusText = sc:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        statusText:SetPoint("LEFT", loadBtn, "RIGHT", 10, 0)
        statusText:SetText("")

        local checkContainer = CreateFrame("Frame", nil, sc)
        checkContainer:SetPoint("TOPLEFT", 35, -800); checkContainer:SetSize(430, 1)

        local checkBoxes = {}
        local checkPool = {}
        local importBtn

        local function ClearChecks()
            for _, cb in pairs(checkBoxes) do cb:Hide() end
            checkBoxes = {}
            if importBtn then importBtn:Hide() end
            statusText:SetText("")
        end

        local function GetPooledCheckbox()
            for _, cb in ipairs(checkPool) do
                if not cb:IsShown() then return cb end
            end
            local cb = W:CreateCheckbox(checkContainer, {
                template = "interface",
            })
            checkPool[#checkPool + 1] = cb
            return cb
        end

        local function BuildChecks(foundKeys)
            ClearChecks()
            if not foundKeys then
                statusText:SetText("|cffff4444Invalid string.|r")
                return
            end

            local yOff = 0
            local count = 0
            for _, m in ipairs(ns.SettingsIO.modules) do
                if foundKeys[m.key] then
                    local cb = GetPooledCheckbox()
                    cb:ClearAllPoints()
                    cb:SetPoint("TOPLEFT", 0, yOff)
                    cb.Text:SetText(m.label)
                    cb:SetChecked(true)
                    cb:Show()
                    checkBoxes[m.key] = cb
                    yOff = yOff - 28
                    count = count + 1
                end
            end

            if count == 0 then
                statusText:SetText("|cffff4444No recognized modules in string.|r")
                return
            end

            statusText:SetText("|cff44ff44" .. count .. " modules found.|r")

            if not importBtn then
                importBtn = W:CreateButton(checkContainer, {
                    text = "Import Selected",
                    width = 130,
                    height = 26,
                    onClick = function()
                        local selected = {}
                        for key, cb in pairs(checkBoxes) do
                            if cb:GetChecked() then selected[key] = true end
                        end
                        local raw = strtrim(importBox:GetText())
                        local ok, err = ns.SettingsIO:Import(raw, selected)
                        if ok then
                            statusText:SetText("|cff44ff44Imported successfully!|r")
                        else
                            statusText:SetText("|cffff4444" .. (err or "Import failed.") .. "|r")
                        end
                    end
                })
            end
            importBtn:ClearAllPoints()
            importBtn:SetPoint("TOPLEFT", 0, yOff - 8)
            importBtn:Show()

            checkContainer:SetHeight(math.abs(yOff) + 40)
        end

        loadBtn:SetScript("OnClick", function()
            local raw = strtrim(importBox:GetText())
            if raw == "" then ClearChecks(); statusText:SetText("|cffff4444Paste a string first.|r"); return end
            local found = ns.SettingsIO:Preview(raw)
            BuildChecks(found)
        end)

    end)
end
