-- HDG_HT_SegmentedBar.lua
-- Discrete-segment fillbar primitive. Replaces WoW StatusBar inside cards
-- (except XP Hero which keeps a smooth bar with non-uniform overlay pips).
-- Two styles: "solid" textured boxes; "blizzPip" Blizzard housing-dashboard atlases.

local _, privateDB = ...
privateDB.HDG_HT = privateDB.HDG_HT or {}
local SegmentedBar = {}
privateDB.HDG_HT.SegmentedBar = SegmentedBar

-- Rounding: nearest 1/N, clamped [0, segments]. Exact 0 = 0; >= 1 = full.
function SegmentedBar.LitCount(pct, segments)
    if pct <= 0 then return 0 end
    if pct >= 1 then return segments end
    local n = math.floor(pct * segments + 0.5)
    if n < 0 then return 0 end
    if n > segments then return segments end
    return n
end

local function applyStyle(seg, style, lit)
    if style == "blizzPip" then
        seg:SetAtlas(lit and "housing-dashboard-fillbar-pip-complete"
                          or "housing-dashboard-fillbar-pip-incomplete")
        seg:SetVertexColor(1, 1, 1, 1)
    elseif style == "circles" then
        -- White circle atlas (from VPP map drawer); tinted per-segment via
        -- _litColor / _unlitColor (gradient when opts.gradient = true).
        seg:SetAtlas("WhiteCircle-RaidBlips")
        local c = lit and seg._litColor or seg._unlitColor
        seg:SetVertexColor(c[1], c[2], c[3], c[4] or 1)
    else
        seg:SetTexture("Interface\\Buttons\\WHITE8x8")
        local c = lit and seg._litColor or seg._unlitColor
        seg:SetVertexColor(c[1], c[2], c[3], c[4] or 1)
    end
end

local function lerp(a, b, t) return a + (b - a) * t end

-- Forward gradient (capacity / running-out): success → warning → error.
-- Reverse gradient (progress / filling-up): warning → success (amber → green).
-- pct ∈ [0,1] is the segment center as a fraction of the bar.
local function gradientColorAt(pct, scheme, reverse)
    local s = (scheme and scheme.success) or { r = 0.40, g = 0.80, b = 0.60 }
    local w = (scheme and scheme.warning) or { r = 1.00, g = 0.78, b = 0.20 }
    if reverse then
        return { lerp(w.r, s.r, pct), lerp(w.g, s.g, pct), lerp(w.b, s.b, pct), 1 }
    end
    local e = (scheme and scheme.error) or { r = 1.00, g = 0.30, b = 0.30 }
    if pct <= 0.5 then
        local t = pct * 2
        return { lerp(s.r, w.r, t), lerp(s.g, w.g, t), lerp(s.b, w.b, t), 1 }
    end
    local t = (pct - 0.5) * 2
    return { lerp(w.r, e.r, t), lerp(w.g, e.g, t), lerp(w.b, e.b, t), 1 }
end

-- opts: { segments=10, segmentHeight=8, gap=2, width=120, style="solid"|"blizzPip",
--         litColor={r,g,b,a}, unlitColor={r,g,b,a} }
function SegmentedBar.Create(parent, opts)
    opts = opts or {}
    local segments      = opts.segments or 10
    local segmentHeight = opts.segmentHeight or 8
    local gap           = opts.gap or 2
    local width         = opts.width or 120
    local style         = opts.style or "solid"
    local gradient      = opts.gradient and true or false
    local gradReverse   = opts.gradientReverse and true or false

    -- Themed defaults: success (lit) + border (unlit). Caller can still override.
    local scheme = (_G.HousingDecorGuide and _G.HousingDecorGuide.Theme
                  and _G.HousingDecorGuide.Theme.GetCurrentScheme()) or nil
    local sSuccess = (scheme and scheme.success) or { r = 0.40, g = 0.80, b = 0.60 }
    local sBorder  = (scheme and scheme.border)  or { r = 0.20, g = 0.20, b = 0.20 }
    local litColor   = opts.litColor   or { sSuccess.r, sSuccess.g, sSuccess.b, 1 }
    local unlitColor = opts.unlitColor or { sBorder.r,  sBorder.g,  sBorder.b,  0.7 }

    -- Floor segment width to integer pixels — fractional offsets cause blurry
    -- segment borders on non-1× UI scales.
    local segWidth = math.floor((width - gap * (segments - 1)) / segments)

    local frame = CreateFrame("Frame", nil, parent)
    frame:SetSize(width, segmentHeight)
    frame.segments = {}
    frame._style = style

    for i = 1, segments do
        local seg = frame:CreateTexture(nil, "ARTWORK")
        seg:SetSize(segWidth, segmentHeight)
        seg:SetPoint("LEFT", frame, "LEFT", (i - 1) * (segWidth + gap), 0)
        if gradient then
            -- Per-segment gradient. Forward = success→warning→error (capacity
            -- running out). Reverse = warning→success (progress filling up).
            seg._litColor = gradientColorAt((i - 0.5) / segments, scheme, gradReverse)
        else
            seg._litColor = litColor
        end
        seg._unlitColor = unlitColor
        applyStyle(seg, style, false)
        frame.segments[i] = seg
    end

    -- Resize the bar to a target width. Returns the actual width applied.
    -- For "circles" style, segment width is locked to segmentHeight (square),
    -- so the bar may be NARROWER than targetWidth. Other styles stretch to
    -- fill targetWidth exactly.
    function frame:Resize(targetWidth)
        local segW
        local actualW
        if style == "circles" then
            segW    = segmentHeight                          -- enforce circle
            actualW = segW * segments + gap * (segments - 1)
        else
            actualW = targetWidth or width
            segW    = math.floor((actualW - gap * (segments - 1)) / segments)
        end
        self:SetWidth(actualW)
        for i, seg in ipairs(self.segments) do
            seg:SetSize(segW, segmentHeight)
            seg:ClearAllPoints()
            seg:SetPoint("LEFT", self, "LEFT", (i - 1) * (segW + gap), 0)
        end
        return actualW
    end

    function frame:Update(pct)
        local lit = SegmentedBar.LitCount(pct, segments)
        for i, seg in ipairs(self.segments) do
            applyStyle(seg, style, i <= lit)
        end
    end

    return frame
end
