-- HousingDecorGuide/UI/Shared/HDG_Carousel.lua
-- Generic horizontal-scroll card carousel. Used by the Crate picker today
-- (top carousel: Blizzard categories; sub carousel: subcategories with
-- progress) and intended for Style Creator's tier strip later.
--
-- Item shape (all fields optional except id + label):
--   {
--     id       = "furnishings",
--     label    = "Furnishings",
--     sublabel = "42/100",           -- right-aligned smaller text under label
--     atlas    = "Atlas-Name",       -- card icon (top-left)
--     icon     = "interface/...",    -- texture-path alternative to atlas
--     progress = 0.42,               -- 0..1; when present a mini bar renders
--     accent   = {r,g,b,a},          -- per-card accent override
--   }
--
-- Usage:
--   local c = HDG_Carousel:Create(parent, {
--       cardWidth = 110, cardHeight = 60, spacing = 6,
--       accent = { r=0.96, g=0.80, b=0.36 },   -- gold (default)
--   })
--   c:SetItems(items)
--   c:SetActive("furnishings")
--   c:SetOnSelect(function(id) ... end)

local _, privateDB = ...
local M = {}
M.__index = M

local DEFAULTS = {
    cardWidth   = 110,
    cardHeight  = 60,
    spacing     = 6,
    accent      = { r = 0.96, g = 0.80, b = 0.36, a = 1 },  -- gold
    bgColor     = { r = 0.06, g = 0.13, b = 0.21, a = 0.85 },
    cardBg      = { r = 0.10, g = 0.18, b = 0.28, a = 0.9 },
}

local function _clone(t)
    local out = {}
    for k, v in pairs(t) do out[k] = v end
    return out
end

local function _merge(base, overrides)
    local out = _clone(base)
    if type(overrides) == "table" then
        for k, v in pairs(overrides) do out[k] = v end
    end
    return out
end

-- ---------------------------------------------------------------------------
-- Card factory
-- ---------------------------------------------------------------------------

local function _ensureCard(self, index)
    local card = self.cards[index]
    if card then return card end

    local opts = self.opts
    card = CreateFrame("Button", nil, self.scrollChild)
    card:SetSize(opts.cardWidth, opts.cardHeight)

    -- Background
    card.bg = card:CreateTexture(nil, "BACKGROUND")
    card.bg:SetAllPoints()
    local cb = opts.cardBg
    card.bg:SetColorTexture(cb.r, cb.g, cb.b, cb.a)

    -- 1px highlight border (drawn via four edge textures)
    card.borders = {}
    for _, side in ipairs({ "TOP", "BOTTOM", "LEFT", "RIGHT" }) do
        local b = card:CreateTexture(nil, "BORDER")
        b:SetColorTexture(1, 1, 1, 0.10)
        if side == "TOP" then
            b:SetHeight(1); b:SetPoint("TOPLEFT"); b:SetPoint("TOPRIGHT")
        elseif side == "BOTTOM" then
            b:SetHeight(1); b:SetPoint("BOTTOMLEFT"); b:SetPoint("BOTTOMRIGHT")
        elseif side == "LEFT" then
            b:SetWidth(1); b:SetPoint("TOPLEFT"); b:SetPoint("BOTTOMLEFT")
        else
            b:SetWidth(1); b:SetPoint("TOPRIGHT"); b:SetPoint("BOTTOMRIGHT")
        end
        card.borders[side] = b
    end

    -- Icon (atlas or texture-path); positioned top-left
    card.icon = card:CreateTexture(nil, "ARTWORK")
    card.icon:SetSize(20, 20)
    card.icon:SetPoint("TOPLEFT", 6, -6)
    card.icon:Hide()

    card.label = card:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    card.label:SetPoint("TOPLEFT", card.icon, "TOPRIGHT", 4, 0)
    card.label:SetPoint("RIGHT", card, "RIGHT", -6, 0)
    card.label:SetJustifyH("LEFT")
    card.label:SetJustifyV("TOP")
    card.label:SetWordWrap(false)

    card.sublabel = card:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
    card.sublabel:SetPoint("BOTTOMLEFT", card, "BOTTOMLEFT", 6, 6)
    card.sublabel:SetJustifyH("LEFT")
    card.sublabel:SetWordWrap(false)
    card.sublabel:SetTextColor(0.7, 0.78, 0.86, 1)

    -- Progress bar (mini, bottom)
    card.progressBg = card:CreateTexture(nil, "ARTWORK")
    card.progressBg:SetHeight(3)
    card.progressBg:SetPoint("BOTTOMLEFT",  card, "BOTTOMLEFT",  6, 1)
    card.progressBg:SetPoint("BOTTOMRIGHT", card, "BOTTOMRIGHT", -6, 1)
    card.progressBg:SetColorTexture(0, 0, 0, 0.4)
    card.progressBg:Hide()

    card.progressFill = card:CreateTexture(nil, "OVERLAY")
    card.progressFill:SetHeight(3)
    card.progressFill:SetPoint("BOTTOMLEFT", card.progressBg, "BOTTOMLEFT", 0, 0)
    card.progressFill:Hide()

    -- Hover tint
    card.hover = card:CreateTexture(nil, "HIGHLIGHT")
    card.hover:SetAllPoints()
    card.hover:SetColorTexture(1, 1, 1, 0.06)

    card:SetScript("OnClick", function(btn)
        if not btn._item then return end
        if btn._item.onClick then btn._item.onClick(btn._item.id, btn._item) end
        if self.onSelect then self.onSelect(btn._item.id, btn._item) end
        self:SetActive(btn._item.id)
    end)

    self.cards[index] = card
    return card
end

local function _applyActiveLook(self, card, isActive)
    local opts = self.opts
    local accent = (card._item and card._item.accent) or opts.accent
    local r, g, b, a = accent.r or 1, accent.g or 1, accent.b or 1, accent.a or 1

    if isActive then
        for _, edge in pairs(card.borders) do
            edge:SetColorTexture(r, g, b, a)
        end
        card.label:SetTextColor(1, 1, 1, 1)
    else
        for _, edge in pairs(card.borders) do
            edge:SetColorTexture(1, 1, 1, 0.10)
        end
        card.label:SetTextColor(0.94, 0.94, 0.94, 1)
    end
end

-- ---------------------------------------------------------------------------
-- Public constructor / API
-- ---------------------------------------------------------------------------

function M:Create(parent, opts)
    local instance = setmetatable({}, M)
    instance.opts = _merge(DEFAULTS, opts)
    instance.cards = {}
    instance.items = {}
    instance.activeID = nil
    instance.onSelect = nil

    local frame = CreateFrame("Frame", nil, parent)
    frame:SetHeight(instance.opts.cardHeight + 8)

    -- Background strip (subtle so the active gold border pops)
    local bg = frame:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints()
    local cbg = instance.opts.bgColor
    bg:SetColorTexture(cbg.r, cbg.g, cbg.b, cbg.a)

    local scrollFrame = CreateFrame("ScrollFrame", nil, frame)
    scrollFrame:SetPoint("TOPLEFT",     frame, "TOPLEFT",      4, -4)
    scrollFrame:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -4,  4)
    scrollFrame:EnableMouseWheel(true)

    local scrollChild = CreateFrame("Frame", nil, scrollFrame)
    scrollChild:SetSize(1, instance.opts.cardHeight)  -- width set in Layout
    scrollFrame:SetScrollChild(scrollChild)

    scrollFrame:SetScript("OnMouseWheel", function(sf, delta)
        local cur = sf:GetHorizontalScroll()
        local maxScroll = math.max(0, scrollChild:GetWidth() - sf:GetWidth())
        local step = (instance.opts.cardWidth + instance.opts.spacing) * 0.75
        local target = math.max(0, math.min(maxScroll, cur - delta * step))
        sf:SetHorizontalScroll(target)
    end)

    instance.frame       = frame
    instance.scrollFrame = scrollFrame
    instance.scrollChild = scrollChild
    return instance
end

function M:GetFrame()
    return self.frame
end

function M:SetItems(items)
    self.items = items or {}
    self:_Layout()
end

function M:SetActive(id)
    self.activeID = id
    for _, card in pairs(self.cards) do
        if card:IsShown() then
            _applyActiveLook(self, card, card._item and card._item.id == id)
        end
    end
end

function M:GetActive()
    return self.activeID
end

function M:SetOnSelect(cb)
    self.onSelect = cb
end

function M:_Layout()
    local opts  = self.opts
    local x     = 0
    local count = #self.items

    -- Hide all cards first; we'll re-bind from items[]
    for _, card in pairs(self.cards) do card:Hide() end

    for i, item in ipairs(self.items) do
        local card = _ensureCard(self, i)
        card._item = item
        card:ClearAllPoints()
        card:SetPoint("TOPLEFT", self.scrollChild, "TOPLEFT", x, 0)

        if item.atlas then
            card.icon:SetAtlas(item.atlas, false)
            card.icon:Show()
        elseif item.icon then
            card.icon:SetTexture(item.icon)
            card.icon:Show()
        else
            card.icon:Hide()
        end

        card.label:SetText(item.label or "")
        if item.sublabel and item.sublabel ~= "" then
            card.sublabel:SetText(item.sublabel)
            card.sublabel:Show()
        else
            card.sublabel:Hide()
        end

        if type(item.progress) == "number" then
            local accent = item.accent or opts.accent
            card.progressBg:Show()
            card.progressFill:Show()
            local pct = math.max(0, math.min(1, item.progress))
            local fullWidth = opts.cardWidth - 12
            card.progressFill:SetWidth(math.max(0.001, fullWidth * pct))
            card.progressFill:SetColorTexture(
                accent.r or 1, accent.g or 1, accent.b or 1, 0.85)
        else
            card.progressBg:Hide()
            card.progressFill:Hide()
        end

        _applyActiveLook(self, card, item.id == self.activeID)
        card:Show()

        x = x + opts.cardWidth + opts.spacing
    end

    self.scrollChild:SetWidth(math.max(1, x - opts.spacing))
    self.scrollChild:SetHeight(opts.cardHeight)
    self.scrollFrame:SetHorizontalScroll(0)

    if count == 0 and self.activeID then
        self.activeID = nil
    end
end

if privateDB then privateDB.HDG_Carousel = M end
return M
