Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.
Revision as of 01:23, 31 January 2026 by Ayaan (talk | contribs)

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

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

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

-- Currency Formatter
local function formatCurrency(amount)
    if not amount then return "0" end
    local n = tonumber(amount) or 0
    local formatted = tostring(n):reverse():gsub("(%d%d%d)(%d%d%d)","%1,%2"):reverse()
    return '<span class="indian-currency">₹ ' .. formatted .. '</span>'
end

-- Social Icons
local function getSocials(args)
    local container = html.create('div'):addClass('fib-socials')
    local hasSocials = false
    local platforms = {
        {arg='instagram', file='Icon_instagram.png', base='https://www.instagram.com/'},
        {arg='twitter',   file='Icon_twitter.png',   base='https://twitter.com/'},
        {arg='youtube',   file='Icon_youtube.png',   base='https://www.youtube.com/'},
        {arg='discord',   file='Icon_discord.png',   base='https://discord.gg/'},
        {arg='facebook',  file='Icon_facebook.png',  base='https://www.facebook.com/'}
    }
    for _, p in ipairs(platforms) do
        local val = args[p.arg]
        if val and val ~= "" then
            hasSocials = true
            local link
            if val:match("^https?://") then
                link = val
            else
                link = p.base .. val
            end
            container:wikitext('[[File:' .. p.file .. '|24px|link=' .. link .. '|linktarget=_blank|class=social-img]]')
        end
    end
    if hasSocials then return tostring(container) else return "" end
end

-- Rank Lookup
local function getKraftonRank(fullPageName, displayName)
    local sqlFull = fullPageName:gsub("'", "\\'")
    local sqlShort = displayName:gsub("'", "\\'")
    local whereClause = string.format("(name = '%s' OR name = '%s') AND type='Player'", sqlFull, sqlShort)
    local results = cargo.query("Krafton_Rankings", "rank", { where = whereClause, limit = 1 })
    if results and #results > 0 then 
        return "#" .. results[1].rank 
    else 
        return "Unranked" 
    end
end

-- ============================================================
-- MAIN 1: PLAYER INFOBOX (WITH EARNINGS BREAKDOWN)
-- ============================================================
function p.infobox(frame)
    local args = frame:getParent().args
    
    -- Variables
    local fullPageName = mw.title.getCurrentTitle().text
    local displayName = args.id or mw.title.getCurrentTitle().subpageText
    local image = args.image or ""
    
    local root = html.create('div'):addClass('flat-infobox')
    
    -- 1. Header
    root:tag('div'):addClass('fib-header')
        :tag('div'):addClass('fib-title'):wikitext(displayName)
    
    -- 2. Image
    local imgContainer = root:tag('div'):addClass('fib-image')
    if image ~= "" then
        imgContainer:wikitext('[[File:' .. image .. '|250px]]')
    else
        imgContainer:wikitext('[[File:Player_Placeholder.png|200px|link=]]')
    end
    
    -- 3. EARNINGS CALCULATION (SEPARATED)
    local individualEarnings = 0
    local teamEarnings = 0
    local sqlNameFull = fullPageName:gsub("'", "\\'")
    local sqlNameShort = displayName:gsub("'", "\\'")

    -- PART A: INDIVIDUAL AWARDS
    if cargo and cargo.query then
        local pWhere = string.format("(player = '%s' OR player = '%s')", sqlNameFull, sqlNameShort)
        local pResults = cargo.query("PrizeMoney", "SUM(prize)=total", { where = pWhere })
        if pResults and #pResults > 0 and pResults[1].total then
            individualEarnings = (tonumber(pResults[1].total) or 0)
        end
    end
    
    -- PART B: TEAM WINNINGS
    if cargo and cargo.query then
        local rosterTable = "Tournament_Teams"
        local rosterFields = "tournament, team"
        local rosterWhere = string.format(
            "p1='%s' OR p1='%s' OR p2='%s' OR p2='%s' OR p3='%s' OR p3='%s' OR p4='%s' OR p4='%s' OR p5='%s' OR p5='%s' OR p6='%s' OR p6='%s'",
            sqlNameFull, sqlNameShort, sqlNameFull, sqlNameShort, sqlNameFull, sqlNameShort,
            sqlNameFull, sqlNameShort, sqlNameFull, sqlNameShort, sqlNameFull, sqlNameShort
        )
        
        local participation = cargo.query(rosterTable, rosterFields, { where = rosterWhere, limit=500 })
        
        if participation and #participation > 0 then
            local prizeConditions = {}
            for _, row in ipairs(participation) do
                if row.tournament and row.team then
                    table.insert(prizeConditions, string.format("(tournament='%s' AND team='%s')", row.tournament:gsub("'", "\\'"), row.team:gsub("'", "\\'")))
                end
            end
            
            if #prizeConditions > 0 then
                local complexWhere = "(" .. table.concat(prizeConditions, " OR ") .. ") AND (player='' OR player IS NULL)"
                local teamPrizes = cargo.query("PrizeMoney", "SUM(prize)=team_total", { where = complexWhere })
                
                if teamPrizes and #teamPrizes > 0 and teamPrizes[1].team_total then
                    teamEarnings = (tonumber(teamPrizes[1].team_total) or 0)
                end
            end
        end
    end

    -- Calculate Total
    local totalEarnings = individualEarnings + teamEarnings

    -- 4. Status & Rank Grid
    local statusColor = "#333"
    local statusText = args.status or "Active"
    if args.status then
        local s = args.status:lower()
        if s == "active" then statusColor = "#16a34a"
        elseif s == "inactive" or s == "banned" or s == "retired" then statusColor = "#dc2626"
        end
    end
    
    local grid1 = root:tag('div'):addClass('fib-grid')
    grid1:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Status'):done():tag('div'):addClass('fib-value-sm'):css('color', statusColor):wikitext(statusText):done()
    
    local rankVal = getKraftonRank(fullPageName, displayName)
    grid1:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Krafton Rank'):done():tag('div'):addClass('fib-value-sm'):wikitext(rankVal):done()

    -- 5. Role & Nation Grid
    local grid2 = root:tag('div'):addClass('fib-grid')
    grid2:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Nationality'):done():tag('div'):addClass('fib-value-sm'):wikitext(args.nationality or 'India'):done()
    grid2:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Role'):done():tag('div'):addClass('fib-value-sm'):wikitext(args.role or 'Player'):done()

    -- 6. Earnings (Highlight WITH BREAKDOWN)
    if totalEarnings > 0 then
        local prizeBox = root:tag('div'):addClass('fib-prize')
        
        -- Main Total
        prizeBox:tag('div'):addClass('fib-label-sm'):wikitext('Approx. Earnings'):done()
        prizeBox:tag('div'):addClass('fib-prize-val'):wikitext(formatCurrency(totalEarnings)):done()
        
        -- Breakdown Sub-Section
        local breakdown = prizeBox:tag('div')
            :css('display', 'flex')
            :css('justify-content', 'space-between')
            :css('margin-top', '8px')
            :css('padding-top', '6px')
            :css('border-top', '1px solid rgba(0,0,0,0.08)')
        
        -- Team Winnings (Left)
        local tDiv = breakdown:tag('div'):css('text-align', 'left')
        tDiv:tag('div'):css('font-size', '0.65em'):css('text-transform', 'uppercase'):css('opacity', '0.7'):wikitext('Team'):done()
        tDiv:tag('div'):css('font-size', '0.85em'):css('font-weight', '600'):wikitext(formatCurrency(teamEarnings)):done()
        
        -- Individual Winnings (Right)
        local iDiv = breakdown:tag('div'):css('text-align', 'right')
        iDiv:tag('div'):css('font-size', '0.65em'):css('text-transform', 'uppercase'):css('opacity', '0.7'):wikitext('Individual'):done()
        iDiv:tag('div'):css('font-size', '0.85em'):css('font-weight', '600'):wikitext(formatCurrency(individualEarnings)):done()
    end
    
    -- 7. Info List
    local list = root:tag('div'):addClass('fib-list')
    local function addRow(label, value)
        if value and value ~= "" then
            list:tag('div'):addClass('fib-row'):tag('div'):addClass('fib-label'):wikitext(label):done():tag('div'):addClass('fib-data'):wikitext(value):done()
        end
    end
    
    addRow('Real Name', args.real_name)
    addRow('Born', args.birth_date)
    if args.current_team then
        addRow('Current Team', '[[' .. args.current_team .. ']]') 
    end
    addRow('Game', args.game or "BGMI")

    -- 8. Team History
    local history = cargo.query("Player_Former_Teams", "team, join_date, leave_date", { 
        where = "player_id = '" .. fullPageName:gsub("'", "\\'") .. "'",
        orderBy = "join_date DESC",
        limit = 10 
    })
    
    if #history > 0 then
        list:tag('div'):addClass('fib-header'):css('font-size','0.95em'):css('padding','10px'):css('margin-top','15px'):css('border-radius','6px'):wikitext('Team History')
        local histTable = list:tag('table'):css('width','100%'):css('font-size','0.9em'):css('border-collapse','collapse'):css('margin-top','5px')
        
        for _, hRow in ipairs(history) do
            local tr = histTable:tag('tr'):css('border-bottom','1px solid #e2e8f0')
            tr:tag('td'):css('padding','8px 4px'):css('font-weight','600'):wikitext('[[' .. hRow.team .. ']]')
            local dates = (hRow.join_date and mw.getContentLanguage():formatDate('M y', hRow.join_date) or '?') .. ' – ' .. (hRow.leave_date and mw.getContentLanguage():formatDate('M y', hRow.leave_date) or 'Now')
            tr:tag('td'):css('text-align','right'):css('padding','8px 4px'):css('color','#64748b'):wikitext(dates)
        end
    else
        -- Fallback check for short name
        local historyShort = cargo.query("Player_Former_Teams", "team, join_date, leave_date", { 
            where = "player_id = '" .. displayName:gsub("'", "\\'") .. "'",
            orderBy = "join_date DESC",
            limit = 10 
        })
        if #historyShort > 0 then
            list:tag('div'):addClass('fib-header'):css('font-size','0.95em'):css('padding','10px'):css('margin-top','15px'):css('border-radius','6px'):wikitext('Team History')
            local histTable = list:tag('table'):css('width','100%'):css('font-size','0.9em'):css('border-collapse','collapse'):css('margin-top','5px')
            for _, hRow in ipairs(historyShort) do
                local tr = histTable:tag('tr'):css('border-bottom','1px solid #e2e8f0')
                tr:tag('td'):css('padding','8px 4px'):css('font-weight','600'):wikitext('[[' .. hRow.team .. ']]')
                local dates = (hRow.join_date and mw.getContentLanguage():formatDate('M y', hRow.join_date) or '?') .. ' – ' .. (hRow.leave_date and mw.getContentLanguage():formatDate('M y', hRow.leave_date) or 'Now')
                tr:tag('td'):css('text-align','right'):css('padding','8px 4px'):css('color','#64748b'):wikitext(dates)
            end
        end
    end

    -- 9. Socials
    root:wikitext(getSocials(args))

    return tostring(root)
end

-- ============================================================
-- MAIN 2: FORMER PLAYERS TABLE
-- ============================================================
function p.formerPlayers(frame)
    local args = frame:getParent().args
    local team = args.team or mw.title.getCurrentTitle().text
    
    local results = cargo.query("Player_Former_Teams, Players", "Player_Former_Teams.player_id=id, Players.real_name=Name, Player_Former_Teams.role=role, Player_Former_Teams.join_date=join_date, Player_Former_Teams.leave_date=leave_date", {
        joinOn = "Player_Former_Teams.player_id = Players._pageName",
        where = "Player_Former_Teams.team = '" .. team:gsub("'", "\\'") .. "' AND Player_Former_Teams.leave_date != ''",
        orderBy = "Player_Former_Teams.leave_date DESC"
    })
    
    local root = html.create('table'):addClass('wikitable flat-table sortable'):css('width','100%')
    local header = root:tag('tr')
    header:tag('th'):wikitext('ID'); header:tag('th'):wikitext('Name'); header:tag('th'):wikitext('Role'); header:tag('th'):wikitext('Duration')
    
    if #results > 0 then
        for _, row in ipairs(results) do
            local tr = root:tag('tr')
            tr:tag('td'):css('font-weight','bold'):wikitext('[[' .. row.id .. ']]')
            tr:tag('td'):wikitext(row.Name)
            tr:tag('td'):wikitext(row.role)
            local range = (row.join_date and mw.getContentLanguage():formatDate('M Y', row.join_date) or '?') .. ' – ' .. (row.leave_date and mw.getContentLanguage():formatDate('M Y', row.leave_date) or '?')
            tr:tag('td'):attr('data-sort-value', row.leave_date):wikitext(range)
        end
    else
        return '<div style="font-style:italic; color:#64748b; padding:10px;">No former players found for this team.</div>'
    end
    
    return tostring(root)
end

return p