-- TOG Tools — Log Graphs (Graphs sub-tab engine + per-log graph specs)
--
-- Registers the "graphs" log sub-category (forced first in the Logs strip
-- via `order`) and owns the mapping from each graphable log to a LogGraph
-- spec (see GUI/LogGraph.lua for the spec contract). Keeping the specs here
-- — rather than in each log's own module — leaves the capture engines
-- untouched and collects all "how this log becomes a chart" logic in one
-- place. v0.6.2 graphs Gathering, Mail, and Trade.
--
-- The Graphs view is read-only: it derives its series on the fly from each
-- log's existing entries, so there's nothing to capture, enable, or clear —
-- it has no Settings toggle and no Clear Data button.

local _, addon = ...

local LogGraphs = {}
addon.logCategories = addon.logCategories or {}
addon.logCategories["graphs"] = LogGraphs

LogGraphs.subKey = "graphs"
LogGraphs.label  = "Graphs"
-- Sort ahead of every capture sub-tab (those have no `order`, treated as
-- 100 by LogsTab). Graphs is the overview, so it leads the strip.
LogGraphs.order  = 0
LogGraphs.help = {
    title = "Logs > Graphs",
    lines = {
        "Line charts of your log data over time, powered by LibGraph. Pick which log to chart with the |cffffd700Log|r dropdown.",
        "|cffffd700Period:|r choose the window — last 24 hours (hourly), 7 / 14 / 30 days (daily), or all time.",
        "|cffffd700Series:|r tick the coloured checkboxes to show/hide individual lines. The totals line below the chart sums each visible series over the period.",
        "|cffffd700Hover the chart|r to see a tooltip for the day (or hour) under your cursor — it lists each visible series' value for just that point.",
        "|cffffd700Gathering:|r one line per gathered item, scoped by the |cffffd700Expansion|r dropdown — so e.g. Midnight shows its own ores. Top items are charted when there are many.",
        "All preferences (period, visible series, expansion) are remembered per log.",
    },
}

-- ---------------------------------------------------------------------------
-- Item-expansion resolution (for the Gathering chart)
-- ---------------------------------------------------------------------------
-- Entries logged from v0.6.2 on carry `expac` (captured at loot time). Older
-- entries don't, so fall back to GetItemInfo's expansionID (15th return),
-- cached per itemID. Returns nil when the item isn't cached yet.
local _expacCache = {}
local function entryExpac(e)
    if e.expac ~= nil then return e.expac end
    local id = e.itemID
    if not id then return nil end
    if _expacCache[id] ~= nil then return _expacCache[id] end
    local expac = GetItemInfo and select(15, GetItemInfo(id)) or nil
    if expac ~= nil then _expacCache[id] = expac end
    return expac
end

local function expacName(id)
    if id == nil then return "Unknown" end
    local nm = _G["EXPANSION_NAME" .. id]
    return nm or ("Expansion " .. tostring(id))
end

local MAX_GRAPH_ITEMS = 12   -- cap per-item series; LogGraph caps too

-- ---------------------------------------------------------------------------
-- Spec builders (lazy category lookups so load order doesn't matter)
-- ---------------------------------------------------------------------------
local function gatheringSpec()
    local cat = addon.logCategories["gathering"]
    if not cat then return nil end
    local function entries() return cat:GetEntries(nil, nil, nil, nil, nil) end

    return {
        key  = "gathering",
        unit = "items",
        getEntries = entries,
        subFilter = {
            label = "Expansion",
            getOptions = function()
                local seen = {}
                for _, e in ipairs(entries()) do
                    local x = entryExpac(e)
                    if x then seen[x] = true end
                end
                local ids = {}
                for id in pairs(seen) do tinsert(ids, id) end
                table.sort(ids, function(a, b) return a > b end)  -- newest first
                local opts = { { value = "__all", text = "All expansions" } }
                for _, id in ipairs(ids) do
                    tinsert(opts, { value = id, text = expacName(id) })
                end
                return opts
            end,
            default = function()
                -- Newest expansion present — that's what the player is most
                -- likely farming right now.
                local maxId
                for _, e in ipairs(entries()) do
                    local x = entryExpac(e)
                    if x and (not maxId or x > maxId) then maxId = x end
                end
                return maxId or "__all"
            end,
        },
        getSeries = function(subVal)
            -- Rank the items in the chosen expansion by total gathered and
            -- chart the top MAX_GRAPH_ITEMS as one line each.
            local agg = {}
            for _, e in ipairs(entries()) do
                if e.itemID and (subVal == "__all" or subVal == nil or entryExpac(e) == subVal) then
                    local a = agg[e.itemID]
                    if not a then a = { id = e.itemID, name = e.name, total = 0 }; agg[e.itemID] = a end
                    a.total = a.total + (e.count or 1)
                end
            end
            local list = {}
            for _, a in pairs(agg) do tinsert(list, a) end
            table.sort(list, function(a, b)
                if a.total ~= b.total then return a.total > b.total end
                return (a.name or "") < (b.name or "")
            end)

            local series = {}
            for i = 1, math.min(#list, MAX_GRAPH_ITEMS) do
                local it = list[i]
                series[i] = {
                    key   = "item:" .. it.id,
                    label = it.name or ("item:" .. it.id),
                    match = function(e) return e.itemID == it.id end,
                    value = function(e) return e.count or 1 end,
                }
            end
            return series
        end,
    }
end

local function mailSpec()
    local cat = addon.logCategories["mail"]
    if not cat then return nil end
    return {
        key  = "mail",
        unit = "mails",
        getEntries = function() return cat:GetEntries(nil, nil, nil, nil) end,
        getSeries = function()
            return {
                { key = "in",  label = "Received", color = {0.30, 1.00, 0.30, 0.9},
                  match = function(e) return e.dir == "in"  end },
                { key = "out", label = "Sent",     color = {0.00, 0.80, 1.00, 0.9},
                  match = function(e) return e.dir == "out" end },
            }
        end,
    }
end

local function tradeSpec()
    local cat = addon.logCategories["trade"]
    if not cat then return nil end
    return {
        key  = "trade",
        unit = "items",
        getEntries = function() return cat:GetEntries(nil, nil, nil) end,
        getSeries = function()
            return {
                { key = "recv", label = "Items received", color = {0.30, 1.00, 0.30, 0.9},
                  match = function(e) return e.received and #e.received > 0 end,
                  value = function(e) return #(e.received or {}) end },
                { key = "give", label = "Items given",    color = {1.00, 0.55, 0.30, 0.9},
                  match = function(e) return e.given and #e.given > 0 end,
                  value = function(e) return #(e.given or {}) end },
            }
        end,
    }
end

-- Ordered, gated list of graphable logs for the picker. Each is included only
-- when its category exists AND its capture is enabled (no point charting a log
-- the user has turned off). label comes from the source category.
local GRAPHABLE = {
    { key = "gathering", build = gatheringSpec },
    { key = "mail",      build = mailSpec },
    { key = "trade",     build = tradeSpec },
}

function LogGraphs:GetGraphableLogs()
    local out = {}
    for _, g in ipairs(GRAPHABLE) do
        local cat = addon.logCategories[g.key]
        if cat and addon:IsLogCategoryEnabled(g.key) then
            local spec = g.build()
            if spec then
                tinsert(out, { key = g.key, label = cat.label or g.key, spec = spec })
            end
        end
    end
    return out
end

-- Per-log graph preference table (period / series visibility / sub-filter),
-- created on demand under db.global.logGraphs.byLog.
function LogGraphs:GetPrefs(logKey)
    local lg = addon.DB and addon.DB.global and addon.DB.global.logGraphs
    if not lg then return { period = 1, series = {} } end
    lg.byLog = lg.byLog or {}
    lg.byLog[logKey] = lg.byLog[logKey] or { period = 1, series = {} }
    return lg.byLog[logKey]
end
