---@diagnostic disable: undefined-field, undefined-global
local _, namespace = ...

local WTUI = namespace.WildThingsUI
local Theme = namespace.Theme

-- A table (never a numeric spellID) so it can never collide with a real candidate value --
-- the dropdown's index-1 "Add spell..." placeholder entry.
local ADD_SENTINEL = {}

local ROW_GAP = 4

-- namespace:CreateSpecCooldownPicker(parent, specID, specName, candidates, onHeightChanged)
-- Self-managing per-spec cooldown picker (READY-05 Settings redesign): a spec header, an
-- "Add spell..." dropdown offering only not-yet-selected candidates, and a wrapping flow of
-- removable pills for the selected spells. Owns its own layout/height via picker:Layout();
-- calls onHeightChanged() after every mutation so the caller (SettingsScreen) can recompute
-- the scroll content height. Reads/writes WildThingsSavedVars.readycheck.cooldown.per_spec
-- (sparse: true = on, nil = off) -- the SAME data model the old per-spec toggle wall used.
function namespace:CreateSpecCooldownPicker(parent, specID, specName, candidates, onHeightChanged)
    local picker = CreateFrame("Frame", nil, parent)

    -- Spec header: re-anchor to sit at the picker's own top (CreateSectionHeader defaults
    -- to anchoring LEFT/RIGHT of its parent, not TOPLEFT/TOPRIGHT).
    local header = namespace:CreateSectionHeader(picker, specName)
    header:ClearAllPoints()
    header:SetPoint("TOPLEFT", picker, "TOPLEFT", 0, 0)
    header:SetPoint("TOPRIGHT", picker, "TOPRIGHT", 0, 0)
    local headerH = header:GetHeight()

    -- Zero-candidate branch: graceful fallback text, no dropdown.
    if not candidates or #candidates == 0 then
        local fallback = picker:CreateFontString(nil, "ARTWORK")
        fallback:SetFontObject(WildThingsFont13)
        fallback:SetTextColor(Theme.TEXT_DIM.r, Theme.TEXT_DIM.g, Theme.TEXT_DIM.b, Theme.TEXT_DIM.a)
        fallback:SetText("No eligible spells for this spec.")
        fallback:SetPoint("TOPLEFT", header, "BOTTOMLEFT", 0, -Theme.GAP)

        function picker:Layout()
            picker:SetHeight(headerH + Theme.GAP + fallback:GetStringHeight())
        end

        return picker
    end

    -- Normal branch: dropdown adder + wrapping pill flow.
    local per = WildThingsSavedVars.readycheck.cooldown.per_spec
    local existing = per[specID]

    local selected = {}
    if existing then
        for spellID in pairs(existing) do
            selected[spellID] = true
        end
    end

    local pills = {}
    local dd

    -- BuildInfoTable(): fresh table, first entry is the non-actionable ADD_SENTINEL
    -- placeholder, followed by one entry per candidate NOT already selected.
    local function BuildInfoTable()
        local info = { { text = "Add spell...", value = ADD_SENTINEL } }

        for _, cand in ipairs(candidates) do
            if not selected[cand.spellID] then
                local candInfo = WTUI.GetSpellInfo(cand.spellID)
                local iconID = candInfo and candInfo.iconID

                info[#info + 1] = {
                    text = ("%s (%ds)"):format(cand.name, cand.cooldown),
                    icon = iconID,
                    value = cand.spellID,
                }
            end
        end

        return info
    end

    local function RemainingCount()
        local count = 0
        for _, cand in ipairs(candidates) do
            if not selected[cand.spellID] then count = count + 1 end
        end
        return count
    end

    local function Placeholder()
        if RemainingCount() > 0 then
            return "Add spell..."
        end
        return "All spells added"
    end

    local function RemovePillFromList(spellID)
        for i, p in ipairs(pills) do
            if p.spellID == spellID then
                table.remove(pills, i)
                break
            end
        end
    end

    -- Forward-declared: OnPick/removeHandler and picker:Layout reference each other
    -- (OnPick creates a pill whose removeHandler is defined below; Layout is defined
    -- after both since it needs `pills`).
    local OnPick

    local function MakeRemoveHandler(removedSpellID)
        return function()
            selected[removedSpellID] = nil
            per[specID][removedSpellID] = nil -- sparse: never write false

            for _, p in ipairs(pills) do
                if p.spellID == removedSpellID then
                    p:Hide()
                    p:SetParent(nil)
                    break
                end
            end
            RemovePillFromList(removedSpellID)

            dd:SetInfoTable(BuildInfoTable())
            dd:OverrideText(Placeholder())

            picker:Layout()
            onHeightChanged()
        end
    end

    local function AddPill(spellID)
        local pill = namespace:CreateCooldownPill(picker, spellID, MakeRemoveHandler(spellID))
        pills[#pills + 1] = pill
        return pill
    end

    OnPick = function(value)
        -- NEUTRALIZE the SetDefaultValue auto-fire gotcha: Dropdown.lua's constructor
        -- calls SetDefaultValue() when built with no initialValue, which selects index 1
        -- and FIRES OnValueChanged -- the sentinel is always index 1, so this guard makes
        -- that auto-fire (and any other sentinel selection) a no-op.
        if value == ADD_SENTINEL then return end

        local spellID = value
        selected[spellID] = true
        per[specID] = per[specID] or {}
        per[specID][spellID] = true

        AddPill(spellID)

        dd:SetInfoTable(BuildInfoTable()) -- rebuild EXCLUDES the now-selected spell; does
                                           -- NOT re-fire OnValueChanged (only the
                                           -- constructor's SetDefaultValue/SetValue path does)
        dd:OverrideText(Placeholder())

        picker:Layout()
        onHeightChanged()
    end

    dd = namespace:CreateDropdown(picker, nil, BuildInfoTable(), OnPick)
    dd:SetPoint("TOPLEFT", header, "BOTTOMLEFT", 0, -Theme.GAP)
    dd:OverrideText(Placeholder())

    -- Seed pills for spells already enabled (existing per_spec entries), so a re-opened
    -- Settings screen reflects prior selections. The dropdown's exclusion already accounts
    -- for `selected` via BuildInfoTable, so no separate rebuild is needed here.
    if existing then
        for spellID in pairs(existing) do
            AddPill(spellID)
        end
    end

    -- picker:Layout(): reflow pills left-to-right within the picker's bound width,
    -- wrapping to a new row when the next pill would overflow. DEFERRED to the caller
    -- (SettingsScreen) to invoke AFTER anchoring the picker -- a wrapping pill flow only
    -- measures correctly once the picker's width is bound (same width-before-measure rule
    -- as BuildWidgets' `text` builder).
    function picker:Layout()
        local availWidth = picker:GetWidth()
        local flowH = 0

        if #pills > 0 and availWidth and availWidth > 0 then
            local pillH = pills[1]:GetHeight()
            local x, row = 0, 0

            for _, pill in ipairs(pills) do
                local pillW = pill:GetWidth()

                if x > 0 and x + pillW > availWidth then
                    x = 0
                    row = row + 1
                end

                local rowY = headerH + Theme.GAP + Theme.H_DROPDOWN + Theme.GAP + row * (pillH + ROW_GAP)

                pill:ClearAllPoints()
                pill:SetPoint("TOPLEFT", picker, "TOPLEFT", x, -rowY)

                x = x + pillW + ROW_GAP
            end

            flowH = (row + 1) * pillH + row * ROW_GAP
        end

        picker:SetHeight(headerH + Theme.GAP + Theme.H_DROPDOWN + Theme.GAP + flowH)
    end

    return picker
end
