Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Documentation for this module may be created at Module:Statistics/doc

local p = {}
local cargo = mw.ext.cargo
local html = mw.html
local text = mw.text

-- ============================================================
-- HELPER: Argument Fetcher
-- ============================================================
local function getArgs(frame)
    local args = {}
    for k, v in pairs(frame.args) do args[k] = v end
    if frame:getParent() then
        for k, v in pairs(frame:getParent().args) do args[k] = v end
    end
    return args
end

-- ============================================================
-- CONFIGURATION
-- ============================================================
local HEADERS = {
    rank = "#", team = "Team", player = "Player", matches_played = "Matches",
    finishes = "Finishes", fpm = "FPM", knocks = "Knocks", damage = "Damage",
    headshots = "Headshots", longest = "Longest", assists = "Assists",
    grenade_kills = "Grenade Fin", vehicle_kills = "Vehicle Fin", contribution = "Contrib %", 
    survival = "Surv. Time", healings = "Heals", revives = "Revives", damage_taken = "Dmg Recv",
    grenades_used = "Nades Used", smokes_used = "Smokes Used", utility_used = "Util Used",
    dist_drive = "Drive Dist", dist_walk = "Walk Dist", dist_total = "Total Dist",
    bluezone = "Bluezone Time", air_drops = "Air Drops",
    total_pts = "Total Pts", place_pts = "Place Pts", elims = "Elims",
    avg_place = "Avg Place", avg_place_pts = "Avg Place Pts", avg_elims = "Avg Elims", avg_total = "Avg Pts",
    wwcd = "🥇", place_2 = "🥈", place_3 = "🥉", top_5 = "Top 5", top_8 = "Top 8", place_low = "> 8th",
    g_0 = "0", g_1_5 = "1–5", g_6_10 = "6–10", g_11_15 = "11–15", g_16_20 = "16–20", g_20_plus = "20+"
}

-- ============================================================
-- HELPER FUNCTIONS
-- ============================================================

local function formatNumber(val)
    if not val then return "" end
    local n = tonumber(val)
    if not n then return val end 
    if n == math.floor(n) then return math.floor(n) else return string.format("%.2f", n) end
end

local function getTeamLogo(teamName)
    if not teamName then return "" end
    local cleanName = teamName:gsub("'", "")
    local lightFile = cleanName .. '.png'
    local darkFile = cleanName .. '_dark.png'
    local hasLight = mw.title.new('File:' .. lightFile).exists
    local hasDark = mw.title.new('File:' .. darkFile).exists
    
    local html = ""
    if hasLight then html = html .. '[[File:' .. lightFile .. '|25px|link=' .. teamName .. '|class=logo-lightmode]]'
    else html = html .. '[[File:Shield_team.png|25px|link=' .. teamName .. '|class=logo-lightmode]]' end
    if hasDark then html = html .. '[[File:' .. darkFile .. '|25px|link=' .. teamName .. '|class=logo-darkmode]]'
    elseif hasLight then html = html .. '[[File:' .. lightFile .. '|25px|link=' .. teamName .. '|class=logo-darkmode]]'
    else html = html .. '[[File:Shield_team_dark.png|25px|link=' .. teamName .. '|class=logo-darkmode]]' end
    return html .. " "
end

-- ============================================================
-- MAIN GENERATOR
-- ============================================================
function p.main(frame)
    local args = getArgs(frame)
    local type = args.type or "player"
    local tournament = args.tournament 
    if not tournament or tournament == "" then tournament = mw.title.getCurrentTitle().text end
    local map = args.map or "All"
    local stage = args.stage
    local group = args.group
    
    local colsInput = args.columns or ""
    local colKeys = {}
    if colsInput == "" then
        if type == "player" then colKeys = {"rank", "player", "team", "matches_played", "finishes", "damage"}
        else colKeys = {"rank", "team", "matches_played", "total_pts", "wwcd"} end
    else colKeys = text.split(colsInput, ",") end
    
    local queryFields = {}
    for _, k in ipairs(colKeys) do
        local cleanK = k:match("^%s*(.-)%s*$")
        if cleanK ~= "rank" then table.insert(queryFields, cleanK) end
    end
    
    local whereParts = {}
    table.insert(whereParts, string.format("tournament='%s'", tournament:gsub("'", "\\'")))
    if map ~= "Any" then table.insert(whereParts, string.format("map='%s'", map:gsub("'", "\\'"))) end
    if stage and stage ~= "" then table.insert(whereParts, string.format("stage='%s'", stage:gsub("'", "\\'"))) end
    if group and group ~= "" then table.insert(whereParts, string.format("groupname='%s'", group:gsub("'", "\\'"))) end
    
    local table_name = (type == "player") and "Player_Stats" or "Team_Stats"
    local selectString = table.concat(queryFields, ",") .. ", team"
    
    local results = cargo.query(table_name, selectString, {
        where = table.concat(whereParts, " AND "),
        orderBy = (type == "player" and "finishes DESC" or "total_pts DESC"),
        limit = 100
    })
    
    if not results or #results == 0 then
        return '<div style="padding:20px; color:var(--text-muted); font-style:italic;">No statistics found for: ' .. table.concat(whereParts, " | ") .. '</div>'
    end
    
    local root = html.create('div'):addClass('stats-table-wrapper')
    local tbl = root:tag('table'):addClass('flat-data-table sortable')
    tbl:css('width', 'auto')
    
    local trHead = tbl:tag('tr')
    for _, key in ipairs(colKeys) do
        local cleanKey = key:match("^%s*(.-)%s*$")
        local label = HEADERS[cleanKey] or cleanKey:upper()
        
        local th = trHead:tag('th'):wikitext(label):css("text-align", "center"):css("white-space", "nowrap")
        
        if cleanKey == "rank" then
            th:addClass('sticky-col sticky-1')
        elseif type == "team" and cleanKey == "team" then
            -- TEAM STATS (PC): Width 220px to fit long names
            th:addClass('sticky-col sticky-2'):css('width', '220px'):css('min-width', '220px'):css('max-width', '220px')
        elseif type == "player" and cleanKey == "player" then
            -- PLAYER STATS (PC): Width 180px for player names
            th:addClass('sticky-col sticky-2'):css('width', '180px'):css('min-width', '180px'):css('max-width', '180px')
        end
    end
    
    for i, row in ipairs(results) do
        local tr = tbl:tag('tr')
        for _, key in ipairs(colKeys) do
            local cleanKey = key:match("^%s*(.-)%s*$")
            local cell = tr:tag('td')
            
            if cleanKey == "rank" then
                cell:addClass('sticky-col sticky-1')
            elseif type == "team" and cleanKey == "team" then
                cell:addClass('sticky-col sticky-2'):css('width', '220px'):css('min-width', '220px'):css('max-width', '220px')
            elseif type == "player" and cleanKey == "player" then
                cell:addClass('sticky-col sticky-2'):css('width', '180px'):css('min-width', '180px'):css('max-width', '180px')
            end

            if cleanKey == "rank" then
                cell:wikitext(i .. '.'):css("font-weight", "bold"):css("text-align", "center"):css("white-space", "nowrap"):css("padding", "5px 0")
            elseif cleanKey == "team" then
                local teamName = row.team or ""
                cell:attr("data-sort-value", teamName)
                if type == "player" then
                    cell:wikitext(getTeamLogo(teamName)):css("text-align", "center")
                else
                    cell:wikitext(getTeamLogo(teamName) .. '[[' .. teamName .. ']]'):css("text-align", "left"):css("white-space", "nowrap")
                end
            elseif cleanKey == "player" then
                cell:wikitext('[[' .. (row.player or "") .. ']]'):css("text-align", "left"):css("font-weight", "bold")
            else
                cell:wikitext(formatNumber(row[cleanKey])):css("text-align", "center")
            end
        end
    end
    return tostring(root)
end

return p