-- =====================================================================
-- Arcfall Marketplace - Price-history Sparkline widget controller
-- ---------------------------------------------------------------------
-- Renders a small line/dots chart of unit price over time inside any
-- UIWidget styled as MarketSparkline (see market.otui).
--
-- Public API (sandbox-global, accessible as
-- modules.game_marketplace.Sparkline):
--     Sparkline.render(widget, points)
--         points = array of { ts = unix-time, value = number }
--     Sparkline.clear(widget)
--
-- Owned by: sparkline agent.  Consumed by detail.lua (Agent B).
-- =====================================================================

Sparkline = {}

-- ---------------------------------------------------------------------
-- Helpers
-- ---------------------------------------------------------------------

-- Compact magnitude formatting: 5K, 120K, 1.5KK ...
local function formatMagnitude(v)
    v = tonumber(v) or 0
    local sign = ''
    if v < 0 then
        sign = '-'
        v = -v
    end
    if v >= 1000000 then
        local s = v / 1000000
        if s >= 100 then
            return sign .. string.format('%dKK', math.floor(s + 0.5))
        elseif s >= 10 then
            return sign .. string.format('%.1fKK', s)
        else
            return sign .. string.format('%.1fKK', s)
        end
    elseif v >= 1000 then
        local s = v / 1000
        if s >= 100 then
            return sign .. string.format('%dK', math.floor(s + 0.5))
        elseif s >= 10 then
            return sign .. string.format('%dK', math.floor(s + 0.5))
        else
            return sign .. string.format('%.1fK', s)
        end
    else
        return sign .. tostring(math.floor(v + 0.5))
    end
end

-- Format a unix timestamp as short date label (e.g. "May 06").
-- CP1252-safe; uses os.date.
local function formatShortDate(ts)
    ts = tonumber(ts)
    if not ts or ts <= 0 then
        return '?'
    end
    return os.date('%b %d', ts)
end

-- Destroy every child widget.  Used both for re-render and for clear().
local function destroyChildren(widget)
    if not widget then return end
    local kids = widget:getChildren()
    for i = #kids, 1, -1 do
        local c = kids[i]
        if c and not c:isDestroyed() then
            c:destroy()
        end
    end
end

-- Show / hide the empty-state label baked into the otui style.
-- If it was destroyed by a previous render we recreate it.
local function ensureEmptyLabel(widget, visible)
    local lbl = widget:getChildById('emptyLabel')
    if not lbl then
        lbl = g_ui.createWidget('Label', widget)
        lbl:setId('emptyLabel')
        lbl:setText('No price history')
        lbl:setColor('#888888')
        lbl:setFont('verdana-11px-antialised')
        lbl:addAnchor(AnchorHorizontalCenter, 'parent', AnchorHorizontalCenter)
        lbl:addAnchor(AnchorVerticalCenter,   'parent', AnchorVerticalCenter)
    end
    lbl:setVisible(visible and true or false)
    return lbl
end

local function renderEmptyState(widget)
    destroyChildren(widget)
    ensureEmptyLabel(widget, true)
end

-- ---------------------------------------------------------------------
-- Public API
-- ---------------------------------------------------------------------

function Sparkline.clear(widget)
    if not widget or widget:isDestroyed() then return end
    destroyChildren(widget)
    ensureEmptyLabel(widget, true)
end

function Sparkline.render(widget, points)
    if not widget or widget:isDestroyed() then return end
    points = points or {}

    -- Empty / single-point: show empty state.
    local n = #points
    if n == 0 or n == 1 then
        renderEmptyState(widget)
        return
    end

    -- Sort defensively by ts ascending.
    table.sort(points, function(a, b)
        return (a.ts or 0) < (b.ts or 0)
    end)

    -- Min / max of values.
    local minV = points[1].value or 0
    local maxV = minV
    for _, p in ipairs(points) do
        local v = p.value or 0
        if v < minV then minV = v end
        if v > maxV then maxV = v end
    end
    if maxV == minV then
        maxV = minV + 1
    end

    -- Trend color (compare last vs first raw value).
    local firstV = points[1].value or 0
    local lastV  = points[n].value or 0
    local dotColor
    if lastV > firstV then
        dotColor = '#66dd66'
    elseif lastV < firstV then
        dotColor = '#ff6666'
    else
        dotColor = '#ffd866'
    end

    -- Resolve widget size; if zero, defer one frame.
    local sz = widget:getSize()
    local W, H = sz.width or 0, sz.height or 0
    if W <= 0 or H <= 0 then
        addEvent(function()
            if widget and not widget:isDestroyed() then
                Sparkline.render(widget, points)
            end
        end)
        return
    end

    -- Wipe old children, hide empty label.
    destroyChildren(widget)
    ensureEmptyLabel(widget, false)

    local PAD_L, PAD_R, PAD_T, PAD_B = 4, 28, 8, 8
    local plotW = W - PAD_L - PAD_R
    local plotH = H - PAD_T - PAD_B
    if plotW < 1 then plotW = 1 end
    if plotH < 1 then plotH = 1 end

    -- Plot the dots.  4x4 colored squares as UIWidgets.
    local DOT = 4
    for i, p in ipairs(points) do
        local fracX = (n == 1) and 0.5 or ((i - 1) / (n - 1))
        local v = p.value or 0
        local fracY = 1 - ((v - minV) / (maxV - minV))
        local x = PAD_L + math.floor(fracX * plotW) - math.floor(DOT / 2)
        local y = PAD_T + math.floor(fracY * plotH) - math.floor(DOT / 2)

        local dot = g_ui.createWidget('UIWidget', widget)
        dot:setSize({width = DOT, height = DOT})
        dot:setPosition({x = widget:getPosition().x + x,
                         y = widget:getPosition().y + y})
        dot:setBackgroundColor(dotColor)
        dot:setBorderWidth(0)
        dot:setPhantom(false)
        dot:setTooltip(formatShortDate(p.ts) .. ': ' .. formatMagnitude(v))
    end

    -- Min / max axis labels at the right edge.
    local maxLbl = g_ui.createWidget('Label', widget)
    maxLbl:setText(formatMagnitude(maxV))
    maxLbl:setColor('#c9c9c9')
    maxLbl:setFont('verdana-11px-antialised')
    maxLbl:setTextAlign(AlignRight)
    maxLbl:setSize({width = PAD_R - 2, height = 12})
    maxLbl:setPosition({x = widget:getPosition().x + W - PAD_R,
                        y = widget:getPosition().y + 1})
    maxLbl:setPhantom(true)

    local minLbl = g_ui.createWidget('Label', widget)
    minLbl:setText(formatMagnitude(minV))
    minLbl:setColor('#c9c9c9')
    minLbl:setFont('verdana-11px-antialised')
    minLbl:setTextAlign(AlignRight)
    minLbl:setSize({width = PAD_R - 2, height = 12})
    minLbl:setPosition({x = widget:getPosition().x + W - PAD_R,
                        y = widget:getPosition().y + H - 13})
    minLbl:setPhantom(true)
end
