interface StandingsEntry { teamId: string; teamName: string; totalPoints: number; rank: number | null; } interface SendStandingsUpdateOptions { webhookUrl: string; seasonName: string; standings: StandingsEntry[]; previousStandings: Map | Record; eventName?: string; } export async function sendStandingsUpdateNotification({ webhookUrl, seasonName, standings, previousStandings, eventName, }: SendStandingsUpdateOptions): Promise { const title = eventName ? `📊 ${seasonName} — Standings after ${eventName}` : `📊 ${seasonName} — Standings Update`; const getPrev = (teamId: string) => previousStandings instanceof Map ? previousStandings.get(teamId) : previousStandings[teamId]; const lines = standings .sort((a, b) => (a.rank ?? 999) - (b.rank ?? 999)) .map((s) => { const prev = getPrev(s.teamId); const diff = prev !== undefined ? s.totalPoints - prev : null; const diffStr = diff !== null && diff !== 0 ? diff > 0 ? ` (+${diff.toFixed(1)})` : ` (${diff.toFixed(1)})` : ""; const rankStr = s.rank != null ? `${s.rank}.` : "-"; return `${rankStr} **${s.teamName}** — ${s.totalPoints.toFixed(1)} pts${diffStr}`; }); const content = [`**${title}**`, "", ...lines].join("\n"); const response = await fetch(webhookUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ content }), }); if (!response.ok) { throw new Error( `Discord webhook returned ${response.status}: ${await response.text()}` ); } }