local ADDON_NAME, ns = ...

local Search = {}
ns.Search = Search

local function Push(idx, entry)
    table.insert(idx, entry)
end

function Search:BuildIndex()
    if self.index then return end
    local idx = {}
    self.index = idx

    if ns.Guides then
        for _, g in ipairs(ns.Guides) do
            Push(idx, {
                label = g.name,
                sub = "Battleground Blitz",
                search = (g.name .. " " .. (g.overview or "")):lower(),
                section = "blitz",
                isGuide = true,
                slug = g.slug,
            })
            local m = ns.GuideMeta and ns.GuideMeta[g.slug]
            if m and m.glance then
                local gtext = table.concat({
                    m.glance.winCondition or "",
                    m.glance.primaryObjective or "",
                    m.glance.openingFocus or "",
                    m.glance.commonMistake or "",
                }, " ")
                Push(idx, {
                    label = g.name .. " - Objectives",
                    sub = "Guide section",
                    search = (g.name .. " " .. gtext):lower(),
                    section = "blitz",
                    isGuide = true,
                    slug = g.slug,
                })
            end
            local c = ns.GuideContent and ns.GuideContent[g.slug]
            if c and c.mistakes then
                Push(idx, {
                    label = g.name .. " - Common Mistakes",
                    sub = "Guide section",
                    search = (g.name .. " " .. table.concat(c.mistakes, " ")):lower(),
                    section = "blitz",
                    isGuide = true,
                    slug = g.slug,
                })
            end
            if m and m.roleCards then
                for role, card in pairs(m.roleCards) do
                    local bits = {}
                    for _, key in ipairs({ "primary", "mistakes", "objectives", "advanced" }) do
                        if card[key] then
                            for _, line in ipairs(card[key]) do table.insert(bits, line) end
                        end
                    end
                    if #bits > 0 then
                        Push(idx, {
                            label = g.name .. " - " .. (role:gsub("^%l", string.upper)),
                            sub = "Role responsibilities",
                            search = (g.name .. " " .. role .. " " .. table.concat(bits, " ")):lower(),
                            section = "blitz",
                            isGuide = true,
                            slug = g.slug,
                        })
                    end
                end
            end
        end
    end

    if ns.Glossary and ns.Glossary.categories then
        for _, cat in ipairs(ns.Glossary.categories) do
            local catTitle = cat.title or cat.id or "Terminology"
            local function indexEntry(e, subTitle)
                local sub = catTitle
                if subTitle and subTitle ~= "" then
                    sub = catTitle .. "  ·  " .. subTitle
                end
                Push(idx, {
                    label = e.term,
                    sub = sub,
                    search = ((e.term or "") .. " " .. (e.def or "") .. " " .. (e.detail or "") .. " " .. (e.search or "")):lower(),
                    section = "terms",
                })
            end
            for _, e in ipairs(cat.entries or {}) do
                indexEntry(e, nil)
            end
            for _, sub in ipairs(cat.subsections or {}) do
                for _, e in ipairs(sub.entries or {}) do
                    indexEntry(e, sub.title)
                end
            end
            if cat.layout == "skirmisher" then
                local specText = {}
                for _, spec in ipairs(cat.specs or {}) do
                    table.insert(specText, spec.label or spec.spec or "")
                end
                Push(idx, {
                    label = catTitle,
                    sub = "Terminology",
                    search = ((cat.title or "") .. " " .. (cat.intro or "") .. " " .. table.concat(cat.traits or {}, " ") .. " " .. table.concat(specText, " ") .. " " .. (cat.search or "")):lower(),
                    section = "terms",
                })
            end
        end
    end

    if ns.MarkerTypes then
        local buffs = {
            "berserking", "restoration", "rune-of-frequency", "cooldown-reset",
            "into-the-shadows", "absorption-shield", "shadow-sight", "runners-boots",
            "random-empowerment",
        }
        for _, cat in ipairs(buffs) do
            local mt = ns.MarkerTypes[cat]
            if mt then
                Push(idx, {
                    label = mt.label or cat,
                    sub = "Buff",
                    search = ((mt.label or "") .. " " .. (mt.tooltip or "")):lower(),
                    section = "buffs",
                })
            end
        end
    end

    if ns.Macros then
        for _, m in ipairs(ns.Macros) do
            Push(idx, {
                label = m.title,
                sub = "Macro",
                search = ((m.title or "") .. " " .. (m.desc or "") .. " " .. table.concat(m.lines or {}, " ")):lower(),
                section = "macros",
            })
        end
    end

end

function Search:HideRows()
    if self.rows then
        for _, r in ipairs(self.rows) do r:Hide() end
    end
end

local function AcquireRow(self, parent, index)
    self.rows = self.rows or {}
    local row = self.rows[index]
    if not row then
        row = CreateFrame("Button", nil, parent)
        row:SetHeight(40)
        row:SetHighlightTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight", "ADD")
        row.label = row:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        row.label:SetPoint("TOPLEFT", 8, -6)
        if NORMAL_FONT_COLOR then row.label:SetTextColor(NORMAL_FONT_COLOR:GetRGB()) end
        row.sub = row:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
        row.sub:SetPoint("TOPLEFT", row.label, "BOTTOMLEFT", 0, -2)
        row.sep = row:CreateTexture(nil, "ARTWORK")
        row.sep:SetColorTexture(0.25, 0.25, 0.25, 0.4)
        row.sep:SetHeight(1)
        row.sep:SetPoint("BOTTOMLEFT", 4, 0)
        row.sep:SetPoint("BOTTOMRIGHT", -4, 0)
        self.rows[index] = row
    end
    row:Show()
    return row
end

local function Navigate(entry)
    local mf = ns.MainFrame
    if entry.isGuide then
        mf:SelectSection("blitz")
        ns.GuideView:OpenGuide(entry.slug)
    else
        mf:SelectSection(entry.section)
    end
    if mf.searchBox then mf.searchBox:SetText("") end
end

function Search:Show(query)
    self:BuildIndex()
    local mf = ns.MainFrame
    mf:ClearContent()
    mf:SetSubnav()
    mf:SetBreadcrumb("Search  >  " .. query)

    query = query:lower()
    local results = {}
    for _, e in ipairs(self.index) do
        if e.search:find(query, 1, true) then
            table.insert(results, e)
        end
    end

    local parent = mf.content
    local width = mf:ContentWidth()
    local intro = mf.builder
    intro:Reset(width)
    if #results == 0 then
        intro:GuideTitle("No results")
        intro:Meta("Nothing matched \"" .. query .. "\".")
        intro:Finish()
        mf:ScrollToTop()
        return
    end
    intro:GuideTitle(#results .. (#results == 1 and " Result" or " Results"))
    local y = intro.y + 4

    for i, e in ipairs(results) do
        local row = AcquireRow(self, parent, i)
        row:ClearAllPoints()
        row:SetPoint("TOPLEFT", 0, -y)
        row:SetPoint("TOPRIGHT", parent, "TOPLEFT", width, -y)
        row.label:SetWidth(width - 16)
        row.label:SetText(e.label)
        row.sub:SetText(e.sub)
        row:SetScript("OnClick", function() Navigate(e) end)
        y = y + 42
    end

    parent:SetHeight(math.max(y + 12, 10))
    mf:ScrollToTop()
end
