import { t } from "./i18n.js";
import { state } from "./state.js";
import { $ } from "./dom.js";
import {
linkRootId,
renderLinkBadge,
escapeHtml,
safeUrl,
} from "./ui-utils.js";
import { scoreToEmoji } from "./votes-ui.js";
import { openLightbox } from "./modals-ui.js";
export function renderResults() {
const container = $("results-list");
if (!container) return;
container.innerHTML = "";
const table = document.createElement("table");
table.className = "results-table";
table.innerHTML = `
| ${t("results.rank")} |
${t("results.game")} |
${t("results.author")} |
${t("results.average")} |
${t("results.votesList")} |
${t("results.myVote")} |
${t("results.links")} |
`;
const tbody = table.querySelector("tbody");
const rankByRoot = new Map();
let nextRank = 1;
state.results.forEach((r) => {
const root = linkRootId(r);
let rank = rankByRoot.get(root);
if (!rank) {
rank = nextRank++;
rankByRoot.set(root, rank);
}
const medal =
rank === 1
? "🥇"
: rank === 2
? "🥈"
: rank === 3
? "🥉"
: `${rank}`;
const row = document.createElement("tr");
const podiumClass =
rank === 1
? "podium podium-1"
: rank === 2
? "podium podium-2"
: rank === 3
? "podium podium-3"
: "";
row.className = podiumClass;
const safeName = escapeHtml(r.name);
const safeAuthor = escapeHtml(r.author ?? "—");
const safeShot = safeUrl(r.screenshotUrl);
const safeGameUrl = safeUrl(r.gameUrl);
const safeYoutubeUrl = safeUrl(r.youtubeUrl);
const votersTooltip = buildVotersTooltip(r);
const safeVotersTooltip = escapeHtml(votersTooltip);
const averageScore =
r.average?.toFixed && typeof r.average === "number"
? r.average.toFixed(1)
: r.average;
row.innerHTML = `
${medal} |
${safeShot ? ` ` : ""}
|
${safeAuthor || "—"} |
${averageScore} |
${formatVotes(r.votes, votersTooltip)} |
${formatMyVote(r.myVote, votersTooltip)} |
${safeGameUrl ? `${t("results.link.site")} ` : ""}
${safeYoutubeUrl ? `${t("results.link.youtube")}` : ""}
|
`;
tbody.appendChild(row);
});
const frame = document.createElement("div");
frame.className = "results-frame";
frame.appendChild(table);
container.appendChild(frame);
container.querySelectorAll(".clickable-thumb").forEach((img) => {
img.addEventListener("click", () => openLightbox(img.src, img.alt));
});
}
function buildResultMeta(r) {
const hasPlayers = r.minPlayers || r.maxPlayers;
const players = hasPlayers
? t("card.players", {
min: r.minPlayers ?? "?",
max: r.maxPlayers ?? "?",
})
: null;
const bits = [r.genre ? escapeHtml(r.genre) : null, players].filter(
Boolean,
);
if (bits.length === 0) return "";
return `${bits.join(" • ")}
`;
}
function formatVotes(votes, tooltip) {
const safeTooltip = escapeHtml(tooltip);
if (!Array.isArray(votes) || votes.length === 0) {
return `⚠️`;
}
const sorted = [...votes].sort((a, b) => a - b);
return sorted
.map(
(v) =>
`${scoreToEmoji(v)}`,
)
.join("");
}
function formatMyVote(score, tooltip) {
if (score == null || Number.isNaN(score)) return "—";
const safeTooltip = escapeHtml(tooltip);
return `${score} ${scoreToEmoji(score)}`;
}
function buildVotersTooltip(result) {
const voterNames = Array.isArray(result?.voterNames)
? result.voterNames
.filter(
(name) => typeof name === "string" && name.trim().length > 0,
)
.sort((a, b) =>
a.localeCompare(b, undefined, { sensitivity: "base" }),
)
: [];
if (voterNames.length === 0) return t("results.votersTooltipEmpty");
return t("results.votersTooltip", { users: voterNames.join(", ") });
}