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:Participant/doc

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

local function sqlEscape(s)
    if not s then return "" end
    s = s:gsub("\\", "\\\\")
    s = s:gsub("'", "\\'")
    return s
end

-- HELPER: Smart Tournament Name Detection
local function getTournamentName(args)
    if args.tournament and args.tournament ~= "" then return args.tournament end
    local pageTitle = mw.title.getCurrentTitle().text
    local parts = mw.text.split(pageTitle, '/')
    if parts[2] == "Tournaments" and parts[3] then return parts[3] end
    return mw.title.getCurrentTitle().baseText
end

-- INTERNAL: Builds the HTML for a single card
local function buildCard(data, seedOverride)
    local root = html.create('div'):addClass('roster-card')

    -- HEADER
    local header = root:tag('div'):addClass('roster-header')
    local headerContent = header:tag('div'):addClass('header-content')

    -- LOGO LOGIC
    -- Priority: 1. Tournament Entry Custom Logo -> 2. Master DB Custom Logo -> 3. Master DB Default Name -> 4. Shield
    local lightLogo = "Shield_team.png"
    local darkLogo = "Shield_team_dark.png"

    -- Check Entry (Tournament specific) Override first
    if data.entryImg and data.entryImg ~= "" then
        lightLogo = data.entryImg
        darkLogo = (data.entryImgDark and data.entryImgDark ~= "") and data.entryImgDark or lightLogo
    -- Check Master DB
    elseif data.masterImg and data.masterImg ~= "" then
        lightLogo = data.masterImg
        darkLogo = (data.masterImgDark and data.masterImgDark ~= "") and data.masterImgDark or lightLogo
    end

    local logoDiv = headerContent:tag('div'):addClass('roster-logo')
    logoDiv:tag('div'):addClass('logo-lightmode'):wikitext('[[File:' .. lightLogo .. '|link=]]')
    logoDiv:tag('div'):addClass('logo-darkmode'):wikitext('[[File:' .. darkLogo .. '|link=]]')

    -- NAME LOGIC
    local displayName = data.displayName
    if not displayName or displayName == "" then displayName = data.team end
    headerContent:tag('div'):addClass('roster-name'):wikitext('[[' .. data.team .. '|' .. displayName .. ']]')

    -- SEEDING
    local finalSeed = seedOverride
    if not finalSeed or finalSeed == "" then finalSeed = data.seeding end
    if finalSeed and finalSeed ~= "" then
        root:tag('div'):addClass('roster-subheader'):wikitext(finalSeed)
    end

    -- PLAYERS
    local contentRows = root:tag('div'):addClass('roster-content-rows')
    local players = {data.p1, data.p2, data.p3, data.p4, data.p5, data.p6}
    local playerCount = 0
    for _, pl in ipairs(players) do if pl and pl ~= "" then playerCount = playerCount + 1 end end

    local playerInner = contentRows:tag('div'):addClass('roster-players-inner'):addClass('count-' .. playerCount)
    for _, pl in ipairs(players) do
        if pl and pl ~= "" then
            playerInner:tag('div'):addClass('roster-row player'):wikitext('[[' .. pl .. ']]')
        end
    end

    -- STAFF
    if (data.coach and data.coach ~= "") or (data.analyst and data.analyst ~= "") then
        local staffInner = contentRows:tag('div'):addClass('roster-staff-inner')
        if data.coach and data.coach ~= "" then staffInner:tag('div'):addClass('roster-row staff'):wikitext('C: [[' .. data.coach .. ']]') end
        if data.analyst and data.analyst ~= "" then staffInner:tag('div'):addClass('roster-row staff'):wikitext('A: [[' .. data.analyst .. ']]') end
    end

    return tostring(root)
end

-- PUBLIC 1: ENTRY MODULE
function p.entry(frame)
    local args = frame:getParent().args
    local count = tonumber(args.count) or 20
    local tournamentName = getTournamentName(args)

    for i = 1, count do
        local prefix = 't' .. i
        local team = args[prefix]
        if team and team ~= "" then
            if cargo and cargo.store then
                cargo.store("Tournament_Teams", {
                    tournament = tournamentName,
                    team = team,
                    display_name = args[prefix .. 'name'],
                    image = args[prefix .. 'img'],
                    image_dark = args[prefix .. 'imgdark'],
                    seeding = args[prefix .. 'seed'],
                    p1 = args[prefix .. 'p1'],
                    p2 = args[prefix .. 'p2'],
                    p3 = args[prefix .. 'p3'],
                    p4 = args[prefix .. 'p4'],
                    p5 = args[prefix .. 'p5'],
                    p6 = args[prefix .. 'p6'],
                    coach = args[prefix .. 'c'],
                    analyst = args[prefix .. 'a']
                })
            end
        end
    end
    return "<div style='display:none;'>Roster Data Saved Successfully.</div>"
end

-- PUBLIC 2: DISPLAY MODULE
function p.display(frame)
    local args = frame:getParent().args
    local tournamentName = getTournamentName(args)
    local count = tonumber(args.count) or 24

    -- 1. Gather Requested Teams
    local requestedTeams = {}
    local orderedRequests = {}

    for i = 1, count do
        local team = args['t' .. i]
        if team and team ~= "" then
            local cleanTeam = sqlEscape(team)
            table.insert(requestedTeams, "'" .. cleanTeam .. "'")
            table.insert(orderedRequests, { name = team, seed = args['t' .. i .. 'seed'] })
        end
    end

    if #requestedTeams == 0 then return "" end
    local teamListSql = table.concat(requestedTeams, ", ")

    -- 2. MEMORY MAP A: Fetch Rosters (Tournament Specific)
    local rosterDb = {}
    if cargo and cargo.query then
        local rResults = cargo.query(
            "Tournament_Teams",
            "team, display_name, image, image_dark, seeding, p1, p2, p3, p4, p5, p6, coach, analyst",
            { where = "tournament='" .. sqlEscape(tournamentName) .. "' AND team IN (" .. teamListSql .. ")", limit = count }
        )
        for _, row in ipairs(rResults) do
            rosterDb[row.team] = row
        end
    end

    -- 3. MEMORY MAP B: Fetch Master Logos (Global Teams Table)
    -- FIXED: We now query 'name' instead of '_pageName' to avoid underscore mismatches
    local masterDb = {}
    if cargo and cargo.query then
        local mResults = cargo.query(
            "Teams",
            "name, image, image_dark", 
            { where = "name IN (" .. teamListSql .. ")", limit = count }
        )
        for _, row in ipairs(mResults) do
            masterDb[row.name] = row
        end
    end

    -- 4. BUILD HTML
    local container = html.create('div')
        :addClass('participant-group-container')
        :css('display', 'flex')
        :css('flex-wrap', 'wrap')
        :css('gap', '15px')
        :css('justify-content', 'center')

    for _, req in ipairs(orderedRequests) do
        local teamName = req.name
        local rosterData = rosterDb[teamName] or { team = teamName }

        -- Merge Master Logos
        if masterDb[teamName] then
            -- 1. If DB has specific image set, use it
            if masterDb[teamName].image and masterDb[teamName].image ~= "" then
                rosterData.masterImg = masterDb[teamName].image
            else
                -- 2. If DB exists but field is blank, assume TeamName.png (Instead of Shield)
                rosterData.masterImg = teamName .. ".png"
            end
            
            -- Dark Mode Logic
            if masterDb[teamName].image_dark and masterDb[teamName].image_dark ~= "" then
                rosterData.masterImgDark = masterDb[teamName].image_dark
            else
                rosterData.masterImgDark = rosterData.masterImg -- Fallback to light
            end
        end

        rosterData.entryImg = rosterData.image
        rosterData.entryImgDark = rosterData.image_dark
        rosterData.displayName = rosterData.display_name

        container:wikitext(buildCard(rosterData, req.seed))
    end

    return tostring(container)
end

return p