local ADDON_NAME, ns = ...

local HubViews = {}
ns.HubViews = HubViews

-- Terminology -----------------------------------------------------------------

local function GlossaryEntryBullets(entry)
    local bullets = {}
    if entry.detail and entry.detail ~= "" then
        table.insert(bullets, entry.detail)
    end
    if entry.example and entry.example ~= "" then
        table.insert(bullets, entry.example)
    end
    if entry.examples and #entry.examples > 0 then
        table.insert(bullets, "Seen on: " .. table.concat(entry.examples, ", "))
    end
    return (#bullets > 0) and bullets or nil
end

local function RenderGlossaryEntry(b, entry)
    b:GlossaryTerm(entry.term or "")
    b:GlossaryDefinition(entry.def)
    b:GlossaryBullets(GlossaryEntryBullets(entry))
end

local function RenderGlossaryTerms(b, entries)
    for _, entry in ipairs(entries or {}) do
        RenderGlossaryEntry(b, entry)
    end
end

local function RenderSkirmisherCategory(b, cat)
    b:GlossaryCategory(cat.title or cat.id)
    if cat.intro and cat.intro ~= "" then
        b:GlossaryDefinition(cat.intro)
    end
    if cat.traits and #cat.traits > 0 then
        b:GlossaryBullets(cat.traits)
    end
    if cat.specs and #cat.specs > 0 then
        b:GlossarySubsection("Common skirmisher specs")
        local labels = {}
        for _, spec in ipairs(cat.specs) do
            table.insert(labels, spec.label or spec.spec or "")
        end
        b:GlossaryBullets(labels)
    end
end

function HubViews:RenderTerms()
    local mf = ns.MainFrame
    mf:ClearContent()
    mf:SetSubnav(nil)
    mf:SetBreadcrumbTrail({ { text = "Home", onClick = function() mf:GoHome() end }, { text = "Terminology" } })
    local b = mf.builder
    b:Reset(mf:ContentWidth())
    b:GuideTitle("Terminology")
    b:Meta("Common PvP and Blitz terms.")

    local gloss = ns.Glossary
    if not gloss or not gloss.categories then
        b:Paragraph("No terminology data loaded.")
        b:Finish(); mf:ScrollToTop(); return
    end

    for _, cat in ipairs(gloss.categories) do
        if cat.layout == "skirmisher" then
            RenderSkirmisherCategory(b, cat)
        else
            b:GlossaryCategory(cat.title or cat.id)
            if cat.intro and cat.intro ~= "" then
                b:GlossaryDefinition(cat.intro)
            end
            RenderGlossaryTerms(b, cat.entries)
            for _, sub in ipairs(cat.subsections or {}) do
                b:GlossarySubsection(sub.title or "")
                RenderGlossaryTerms(b, sub.entries)
            end
        end
    end
    b:Finish()
    mf:ScrollToTop()
end

-- Buffs -----------------------------------------------------------------------

local BUFF_ORDER = {
    "berserking", "restoration", "rune-of-frequency", "cooldown-reset",
    "into-the-shadows", "absorption-shield", "shadow-sight", "runners-boots",
    "random-empowerment",
}

local function BuffAppearsOn(cat)
    local names = {}
    local seen = {}
    if ns.MapData then
        for slug, map in pairs(ns.MapData) do
            if map.markers then
                for _, m in ipairs(map.markers) do
                    if m.category == cat and not seen[slug] then
                        seen[slug] = true
                        local g = ns.GuideBySlug and ns.GuideBySlug[slug]
                        table.insert(names, (g and g.name) or slug)
                    end
                end
            end
        end
    end
    table.sort(names)
    return names
end

function HubViews:RenderBuffs()
    local mf = ns.MainFrame
    mf:ClearContent()
    mf:SetSubnav(nil)
    mf:SetBreadcrumbTrail({ { text = "Home", onClick = function() mf:GoHome() end }, { text = "Buffs" } })
    local b = mf.builder
    b:Reset(mf:ContentWidth())
    b:GuideTitle("Buffs")
    b:Meta("Pickups and runes across Battleground Blitz maps.")
    b:Spacer(4)

    local types = ns.MarkerTypes or {}
    for _, cat in ipairs(BUFF_ORDER) do
        local mt = types[cat]
        if mt then
            local bullets = {}
            if mt.tooltipBlocks then
                for _, blk in ipairs(mt.tooltipBlocks) do
                    local blkType = types[blk.category]
                    local prefix = (blkType and blkType.label) or blk.category
                    table.insert(bullets, "|cffb8a4e8" .. prefix .. ":|r " .. blk.text)
                end
            end
            local appears = BuffAppearsOn(cat)
            if #appears > 0 then
                table.insert(bullets, "Appears on: " .. table.concat(appears, ", "))
            end
            b:Card({
                type = "rec",
                icon = ns.UI.BUFF_ICONS[cat],
                title = mt.label or cat,
                body = mt.tooltip or mt.tooltipHead,
                bullets = (#bullets > 0) and bullets or nil,
            })
        end
    end
    b:Finish()
    mf:ScrollToTop()
end

-- Macros ----------------------------------------------------------------------

local MACRO_PAD = 10
local MACRO_ICON = 32
local MACRO_ICON_GAP = 8
local MACRO_COL_GAP = 10
local MACRO_ROW_GAP = 10
local MACRO_MIN_CARD = 240
local MACRO_MAX_CARD = 320
local MACRO_COPY_W = 70
local MACRO_COPY_H = 20

local function MacroText(macro)
    return table.concat(macro.lines or {}, "\n")
end

-- Prefer live item icon file IDs; fall back to a known Interface\Icons name.
local function MacroIconTexture(macro)
    local itemId = macro and macro.itemId
    if itemId then
        local fileId
        if GetItemInfoInstant then
            local _, _, _, _, icon = GetItemInfoInstant(itemId)
            fileId = icon
        end
        if not fileId and C_Item and C_Item.GetItemIconByID then
            fileId = C_Item.GetItemIconByID(itemId)
        end
        if not fileId and GetItemIcon then
            fileId = GetItemIcon(itemId)
        end
        if fileId and fileId ~= 0 then
            return fileId, false
        end
    end
    local icon = macro and (macro.icon or macro.titleIcon)
    if type(icon) == "string" and icon ~= "" and ns.UI and ns.UI.ResolveIcon then
        return ns.UI.ResolveIcon(icon)
    end
    return nil, false
end

function HubViews:HideMacroRows()
    if self.macroRows then
        for _, r in ipairs(self.macroRows) do r:Hide() end
    end
end

local function AcquireMacroRow(self, parent, index)
    self.macroRows = self.macroRows or {}
    local row = self.macroRows[index]
    if not row then
        row = CreateFrame("Frame", nil, parent, "BackdropTemplate")
        row:SetBackdrop({
            bgFile = "Interface\\Buttons\\WHITE8x8",
            edgeFile = "Interface\\Buttons\\WHITE8x8",
            edgeSize = 1,
        })
        row:SetBackdropColor(0, 0, 0, 0.28)
        row:SetBackdropBorderColor(0.32, 0.48, 0.32, 0.45)

        -- Subtle square icon tile (Blizzard ability-entry style).
        row.iconBG = row:CreateTexture(nil, "ARTWORK", nil, 1)
        row.iconBG:SetColorTexture(0, 0, 0, 0.55)
        row.iconBG:SetSize(MACRO_ICON + 2, MACRO_ICON + 2)
        row.icon = row:CreateTexture(nil, "ARTWORK", nil, 2)
        row.icon:SetSize(MACRO_ICON, MACRO_ICON)
        row.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
        row.icon:SetPoint("CENTER", row.iconBG, "CENTER", 0, 0)

        row.title = row:CreateFontString(nil, "OVERLAY", "GameFontNormalMed3")
        row.title:SetJustifyH("LEFT")
        row.title:SetJustifyV("TOP")
        row.title:SetTextColor(0.95, 0.93, 0.90)

        row.desc = row:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        row.desc:SetJustifyH("LEFT")
        row.desc:SetJustifyV("TOP")
        row.desc:SetTextColor(0.82, 0.82, 0.82)

        row.body = row:CreateFontString(nil, "OVERLAY", "ChatFontNormal")
        row.body:SetJustifyH("LEFT")
        row.body:SetJustifyV("TOP")
        row.body:SetSpacing(2)
        row.body:SetTextColor(0.72, 0.90, 0.72)

        row.copy = CreateFrame("Button", nil, row, "UIPanelButtonTemplate")
        row.copy:SetSize(MACRO_COPY_W, MACRO_COPY_H)
        row.copy:SetText("Copy")

        self.macroRows[index] = row
    end
    row:Show()
    return row
end

local function LayoutMacroCard(row, macro, cardW)
    local path = MacroIconTexture(macro)
    local hasIcon = path ~= nil
    local textLeft = MACRO_PAD
    if hasIcon then
        row.iconBG:ClearAllPoints()
        row.iconBG:SetPoint("TOPLEFT", MACRO_PAD, -MACRO_PAD)
        row.iconBG:Show()
        row.icon:SetTexture(path)
        row.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
        row.icon:Show()
        textLeft = MACRO_PAD + MACRO_ICON + 2 + MACRO_ICON_GAP
    else
        row.iconBG:Hide()
        row.icon:Hide()
    end

    local titleW = math.max(cardW - textLeft - MACRO_PAD, 40)
    row.title:ClearAllPoints()
    row.title:SetPoint("TOPLEFT", textLeft, -MACRO_PAD)
    row.title:SetWidth(titleW)
    row.title:SetText(macro.title or "Macro")

    local titleH = row.title:GetStringHeight()
    local headerH = hasIcon and math.max(MACRO_ICON + 2, titleH) or titleH
    local y = MACRO_PAD + headerH + 4

    local contentW = math.max(cardW - MACRO_PAD * 2, 40)
    row.desc:ClearAllPoints()
    row.desc:SetPoint("TOPLEFT", MACRO_PAD, -y)
    row.desc:SetWidth(contentW)
    row.desc:SetText(macro.desc or "")
    y = y + row.desc:GetStringHeight() + 8

    local bodyText = MacroText(macro)
    row.body:ClearAllPoints()
    row.body:SetPoint("TOPLEFT", MACRO_PAD, -y)
    row.body:SetWidth(contentW)
    row.body:SetText(bodyText)
    y = y + row.body:GetStringHeight() + 10

    row.copy:ClearAllPoints()
    row.copy:SetPoint("BOTTOMRIGHT", -MACRO_PAD, MACRO_PAD)

    local h = y + MACRO_COPY_H + MACRO_PAD
    row:SetWidth(cardW)
    row:SetHeight(math.max(h, hasIcon and (MACRO_PAD * 2 + MACRO_ICON + 2) or 60))
    return bodyText
end

function HubViews:RenderMacros()
    local mf = ns.MainFrame
    mf:ClearContent()
    mf:SetSubnav(nil)
    mf:SetBreadcrumbTrail({ { text = "Home", onClick = function() mf:GoHome() end }, { text = "Macros" } })
    local width = mf:ContentWidth()
    local parent = mf.content

    local intro = mf.builder
    intro:Reset(width)
    intro:GuideTitle("Macros")
    intro:Meta("Copy into the game macro editor.")
    local y = intro.y

    local twoCol = (width - MACRO_COL_GAP) >= (MACRO_MIN_CARD * 2)
    local cardW
    if twoCol then
        cardW = math.min(MACRO_MAX_CARD, math.floor((width - MACRO_COL_GAP) / 2))
    else
        cardW = math.min(MACRO_MAX_CARD, width)
    end

    local macros = ns.Macros or {}
    local col = 0
    local rowY = y
    local rowMaxH = 0

    for i, macro in ipairs(macros) do
        local row = AcquireMacroRow(self, parent, i)
        local bodyText = LayoutMacroCard(row, macro, cardW)
        local title = macro.title or "Macro"
        row.copy:SetScript("OnClick", function() ns.CopyDialog:Open(title, bodyText, "macro") end)

        local x = col * (cardW + MACRO_COL_GAP)
        row:ClearAllPoints()
        row:SetPoint("TOPLEFT", x, -rowY)

        local h = row:GetHeight()
        if twoCol then
            rowMaxH = math.max(rowMaxH, h)
            col = col + 1
            if col > 1 then
                col = 0
                rowY = rowY + rowMaxH + MACRO_ROW_GAP
                rowMaxH = 0
            end
        else
            rowY = rowY + h + MACRO_ROW_GAP
        end
    end
    if twoCol and col == 1 then
        rowY = rowY + rowMaxH + MACRO_ROW_GAP
    end

    for i = #macros + 1, #(self.macroRows or {}) do
        self.macroRows[i]:Hide()
    end

    parent:SetHeight(math.max(rowY + 8, 10))
    mf:ScrollToTop()
end

-- Resources -------------------------------------------------------------------

function HubViews:RenderResources()
    local mf = ns.MainFrame
    mf:ClearContent()
    mf:SetSubnav(nil)
    mf:SetBreadcrumbTrail({ { text = "Home", onClick = function() mf:GoHome() end }, { text = "Resources" } })
    local b = mf.builder
    b:Reset(mf:ContentWidth())

    b:GuideTitle("Resources")
    b:Meta("Addons, websites, and creators.")

    b:Heading("Recommended Addons")
    for _, a in ipairs(ns.Addons or {}) do
        b:Card({ type = "info", icon = ns.UI.RESOURCE_ICONS.addon, title = a.name, body = a.desc, link = a.url, linkLabel = "Copy CurseForge link" })
    end

    b:Heading("Useful Websites")
    for _, w in ipairs(ns.Websites or {}) do
        b:Card({ type = "info", icon = ns.UI.RESOURCE_ICONS.website, title = w.name, body = w.desc, link = w.url, linkLabel = "Copy website link" })
    end

    b:Heading("Content Creators")
    for _, c in ipairs(ns.Creators or {}) do
        local bullets = {}
        if c.categories then table.insert(bullets, "Focus: " .. table.concat(c.categories, ", ")) end
        local primary
        if c.links then
            for _, l in ipairs(c.links) do
                table.insert(bullets, "|cFF8DB4E2" .. (l.label or l.platform or "Link") .. ":|r " .. l.url)
                if not primary then primary = l end
            end
        end
        b:Card({
            type = "rec",
            icon = ns.UI.RESOURCE_ICONS.creator,
            title = c.name .. (c.region and ("  |cFF999999(" .. c.region .. ")|r") or ""),
            body = c.desc,
            bullets = (#bullets > 0) and bullets or nil,
            link = primary and primary.url or nil,
            linkLabel = primary and ("Copy " .. (primary.label or "link")) or nil,
        })
    end
    b:Finish()
    mf:ScrollToTop()
end
