-- TOG Tools — Trade Log sub-tab (UI)
-- Renders inside the Logs outer tab's nested AceGUI TabGroup. Layout
-- mirrors the Mail sub-tab — filter row over a RowList — but the table
-- is two-sided so each trade shows both Given and Received cells, plus
-- a dedicated Enchant column for trade slot 7 (often empty; visible
-- when applying an enchant to/from a partner's item).
--
-- Per-session filter state lives on the module table; not persisted.

local _, addon = ...
local AceGUI = LibStub("AceGUI-3.0")

local TradeLog = addon.logCategories["trade"]

TradeLog._filterPlayer       = TradeLog._filterPlayer       or nil
TradeLog._filterRange        = TradeLog._filterRange        or addon.DateRangePicker.DEFAULT_KEY
TradeLog._filterCustomFrom   = TradeLog._filterCustomFrom   or nil
TradeLog._filterCustomTo     = TradeLog._filterCustomTo     or nil
TradeLog._filterCalendarOpen = TradeLog._filterCalendarOpen or false

-- ---------------------------------------------------------------------------
-- Cell formatters
-- ---------------------------------------------------------------------------
local function fmtTime(ts)
    if not ts or ts <= 0 then return "—" end
    local now = (GetServerTime and GetServerTime()) or time()
    local diff = now - ts
    if diff < 60      then return string.format("%ds ago", math.floor(diff)) end
    if diff < 3600    then return string.format("%dm ago", math.floor(diff / 60)) end
    if diff < 86400   then return string.format("%dh ago", math.floor(diff / 3600)) end
    if diff < 604800  then return string.format("%dd ago", math.floor(diff / 86400)) end
    return date("%m/%d/%y", ts)
end

local function fmtMoney(copper)
    if not copper or copper <= 0 then return nil end
    local g = math.floor(copper / 10000)
    local s = math.floor((copper % 10000) / 100)
    local c = copper % 100
    local parts = {}
    if g > 0 then tinsert(parts, "|cffffd700" .. g .. "g|r") end
    if s > 0 then tinsert(parts, "|cffc7c7cf" .. s .. "s|r") end
    if c > 0 and g == 0 then tinsert(parts, "|cffeda55f" .. c .. "c|r") end
    return table.concat(parts, " ")
end

local function fmtSide(items, money)
    -- One side of the trade — items + money rolled into one cell. Lead
    -- with the first item link; collapse extras into "+N more" so the
    -- column stays readable when several items were traded.
    local hasItems = items and #items > 0
    local moneyStr = fmtMoney(money)
    if not hasItems and not moneyStr then return "|cff888888—|r" end
    local parts = {}
    if hasItems then
        local first = items[1]
        local s = first.link or ""
        if (first.count or 1) > 1 then s = s .. " x" .. first.count end
        if #items > 1 then s = s .. " |cffaaaaaa+" .. (#items - 1) .. " more|r" end
        tinsert(parts, s)
    end
    if moneyStr then tinsert(parts, moneyStr) end
    return table.concat(parts, ", ")
end

local function fmtEnchant(given, received)
    -- Visible when slot 7 was used on either side. "→" for given to
    -- partner; "←" for received from partner. Both is unusual but
    -- handled (mutual enchant trade).
    if given and received then
        return "|cffaa44ff->|r " .. given .. " |cffaa44ff/ <-|r " .. received
    end
    if given    then return "|cffaa44ff->|r " .. given    end
    if received then return "|cffaa44ff<-|r " .. received end
    return "|cff888888—|r"
end

-- ---------------------------------------------------------------------------
-- Two-step Clear confirm (same pattern as Mail Log)
-- ---------------------------------------------------------------------------
local CONFIRM_SEC = 5
local function attachClearConfirm(button, onConfirm)
    local pending = false
    local ticker
    local function reset()
        pending = false
        button:SetText("Clear data")
        if ticker then ticker:Cancel(); ticker = nil end
    end
    reset()
    button:SetCallback("OnClick", function()
        if pending then
            reset()
            onConfirm()
            return
        end
        pending = true
        local remaining = CONFIRM_SEC
        button:SetText(string.format("|cffff5555Really? (%ds)|r", remaining))
        ticker = C_Timer.NewTicker(1, function()
            remaining = remaining - 1
            if remaining <= 0 then reset() return end
            button:SetText(string.format("|cffff5555Really? (%ds)|r", remaining))
        end, CONFIRM_SEC)
    end)
    button:SetCallback("OnRelease", function()
        if ticker then ticker:Cancel(); ticker = nil end
    end)
end

-- ---------------------------------------------------------------------------
-- Filter dropdowns
-- ---------------------------------------------------------------------------
local function buildPlayerDropdown(onChange)
    local dd = AceGUI:Create("Dropdown")
    dd:SetLabel("Character")
    dd:SetWidth(180)
    local list, order = { __all = "All characters" }, { "__all" }
    for _, k in ipairs(TradeLog:GetPlayerKeys()) do
        list[k] = k
        tinsert(order, k)
    end
    dd:SetList(list, order)
    dd:SetValue(TradeLog._filterPlayer or "__all")
    dd:SetCallback("OnValueChanged", function(_, _, key)
        TradeLog._filterPlayer = (key == "__all") and nil or key
        onChange()
    end)
    return dd
end

-- ---------------------------------------------------------------------------
-- Draw
-- ---------------------------------------------------------------------------
function TradeLog:Draw(container)
    container:SetLayout("Flow")

    local function rebuild()
        if addon.MainWindow and addon.MainWindow.Refresh then
            addon.MainWindow:Refresh()
        end
    end

    -- ---- Filter row -----------------------------------------------------
    local filterRow = AceGUI:Create("SimpleGroup")
    filterRow:SetFullWidth(true)
    filterRow:SetLayout("Flow")
    container:AddChild(filterRow)

    filterRow:AddChild(buildPlayerDropdown(rebuild))
    filterRow:AddChild(addon.DateRangePicker:Create({
        default  = self._filterRange,
        onChange = function(key)
            local enteringCustom = (key == "custom" and self._filterRange ~= "custom")
            self._filterRange = key
            if enteringCustom then self._filterCalendarOpen = true end
            rebuild()
        end,
    }))

    if self._filterRange == "custom" and self._filterCustomFrom
       and not self._filterCalendarOpen then
        local pickBtn = AceGUI:Create("Button")
        pickBtn:SetWidth(140)
        pickBtn:SetText("Pick range...")
        pickBtn:SetCallback("OnClick", function()
            self._filterCalendarOpen = true
            rebuild()
        end)
        filterRow:AddChild(pickBtn)
    end

    local clearBtn = AceGUI:Create("Button")
    clearBtn:SetWidth(140)
    attachClearConfirm(clearBtn, function()
        TradeLog:ClearAll()
        rebuild()
    end)
    filterRow:AddChild(clearBtn)

    if self._filterRange == "custom"
       and (not self._filterCustomFrom or self._filterCalendarOpen) then
        local unbounded = TradeLog:GetEntries(self._filterPlayer, nil, nil)
        local timestamps = {}
        for _, e in ipairs(unbounded) do tinsert(timestamps, e.ts) end
        container:AddChild(addon.DateRangePicker:CreateCalendar({
            defaultFrom = self._filterCustomFrom,
            defaultTo   = self._filterCustomTo,
            timestamps  = timestamps,
            onApply     = function(fromTs, toTs)
                self._filterCustomFrom   = fromTs
                self._filterCustomTo     = toTs
                self._filterCalendarOpen = false
                rebuild()
            end,
        }))
        if not self._filterCustomFrom then return end
    end

    -- Spacer between filter row and the data table
    local sp = AceGUI:Create("Label")
    sp:SetFullWidth(true); sp:SetText(" ")
    container:AddChild(sp)

    -- ---- Data table -----------------------------------------------------
    local body = AceGUI:Create("SimpleGroup")
    body:SetFullWidth(true)
    body:SetFullHeight(true)
    body:SetLayout("List")
    container:AddChild(body)

    local fromTs, toTs = addon.DateRangePicker:Resolve(
        self._filterRange, self._filterCustomFrom, self._filterCustomTo)
    local entries = TradeLog:GetEntries(self._filterPlayer, fromTs, toTs)

    if #entries == 0 then
        local empty = AceGUI:Create("Label")
        empty:SetFullWidth(true)
        empty:SetText("|cff888888No trade entries match the current filters.|r\n\nTrade Log captures every completed player-to-player trade — arena/BG trades are skipped intentionally. Try widening the date range or selecting |cffffd700All characters|r.")
        body:AddChild(empty)
        return
    end

    local rl = addon.RowList:New(body.content, {
        rowHeight = 16,
        columns = {
            { key = "ts", header = "Time", autoFit = true, minWidth = 50, justify = "LEFT",
              sortKey = "ts", sortDescDefault = true,
              headerTip = "Time",
              headerTipDesc = "When the trade completed. Recent entries show as \"Nm/h/d ago\"; older entries fall back to MM/DD/YY. Click to sort by time. Column auto-sizes to fit the longest visible timestamp.",
              format = function(e) return fmtTime(e.ts) end },

            { key = "player", header = "Character", autoFit = true, minWidth = 60, justify = "LEFT",
              headerTip = "Character",
              headerTipDesc = "The alt that completed this trade. Trade Log is account-wide; use the Character filter dropdown above to narrow to one alt. Column auto-sizes to fit the longest visible name.",
              format = function(e) return e.player or "?" end },

            { key = "other", header = "Partner", autoFit = true, minWidth = 60, justify = "LEFT",
              headerTip = "Partner",
              headerTipDesc = "The player on the other side of the trade. Cross-realm trades show the partner's full Name-Realm; same-realm trades may omit the realm suffix. Column auto-sizes to fit the longest visible partner.",
              format = function(e) return e.other or "?" end },

            { key = "given", header = "Given", justify = "LEFT",
              headerTip = "Given",
              headerTipDesc = "What YOU handed over: items + money. Leads with the first item link; multi-item trades show \"+N more\". Money appended after items with gold/silver/copper colouring. This is the rightmost-of-left-cluster stretchy column — the one that may truncate when the window is too narrow; every other column auto-sizes to fit its content.",
              format = function(e) return fmtSide(e.given, e.moneyGiven) end },

            { key = "received", header = "Received", autoFit = true, minWidth = 70, justify = "LEFT",
              headerTip = "Received",
              headerTipDesc = "What the PARTNER handed over to you: items + money. Same format as Given. Column auto-sizes to fit the longest visible received bundle.",
              format = function(e) return fmtSide(e.received, e.moneyReceived) end },

            { key = "enchant", header = "Enchant", autoFit = true, minWidth = 50, justify = "LEFT",
              headerTip = "Enchant",
              headerTipDesc = "Trade slot 7 contents (the enchant slot). |cffaa44ff->|r = enchant applied to partner's item; |cffaa44ff<-|r = partner applied an enchant to your item; both arrows = mutual enchant trade. Usually empty. Column auto-sizes to fit the longest visible enchant.",
              format = function(e) return fmtEnchant(e.enchantGiven, e.enchantReceived) end },
        },
    })
    rl:SetSort("ts", true)
    rl:SetData(entries)

    body:SetCallback("OnRelease", function() rl:Detach() end)
end
