import { HttpError } from "../middleware/errors.js"; import { getGame, listByDate, type GameWithId } from "../repositories/gameRepository.js"; import { getUserVote, submitVote, changeVote, getCounts, getUserDateVotes, } from "../repositories/voteRepository.js"; import type { Game, VoteEntry } from "../types/panit.js"; import { fromTimestamp, parseDateString, type DateString } from "../types/dateString.js"; function gameDate(game: Game): DateString { return fromTimestamp(game.time); } function sideOf(game: Game, teamCode: string): "home" | "away" { if (teamCode === game.homeTeamCode) return "home"; if (teamCode === game.awayTeamCode) return "away"; throw new HttpError(400, `teamCode ${teamCode} not in game ${game.homeTeamCode}/${game.awayTeamCode}`); } async function loadWaitingGame(gameId: string): Promise { const game = await getGame(gameId); if (!game) throw new HttpError(404, `game not found: ${gameId}`); if (game.status !== "waiting") { throw new HttpError(409, `game status is ${game.status}, voting closed`); } return game; } export async function createPrediction( uid: string, body: { gameId?: string; selectedTeamCode?: string } ): Promise<{ ok: true }> { if (!body.gameId || !body.selectedTeamCode) { throw new HttpError(400, "gameId and selectedTeamCode required"); } const game = await loadWaitingGame(body.gameId); const side = sideOf(game, body.selectedTeamCode); const existing = await getUserVote(body.gameId, uid); if (existing) throw new HttpError(409, "already voted; use PUT to change"); await submitVote({ gameId: body.gameId, uid, date: gameDate(game), side, team: body.selectedTeamCode, }); return { ok: true }; } export async function updatePrediction( uid: string, body: { gameId?: string; selectedTeamCode?: string } ): Promise<{ ok: true; changed: boolean }> { if (!body.gameId || !body.selectedTeamCode) { throw new HttpError(400, "gameId and selectedTeamCode required"); } const game = await loadWaitingGame(body.gameId); const newSide = sideOf(game, body.selectedTeamCode); const existing = await getUserVote(body.gameId, uid); if (!existing) throw new HttpError(400, "no prior vote; use POST"); if (existing.team === body.selectedTeamCode) return { ok: true, changed: false }; const oldSide = sideOf(game, existing.team); await changeVote({ gameId: body.gameId, uid, date: gameDate(game), oldSide, newSide, newTeam: body.selectedTeamCode, }); return { ok: true, changed: true }; } export async function getMyVotes( uid: string, date: string ): Promise> { try { return getUserDateVotes(uid, parseDateString(date)); } catch (err) { throw new HttpError(400, (err as Error).message); } } export async function listGamesByDate(date: string): Promise { try { return await listByDate(parseDateString(date)); } catch (err) { throw new HttpError(400, (err as Error).message); } } export async function getSummary( gameId: string ): Promise<{ homeCount: number; awayCount: number }> { if (!gameId) throw new HttpError(400, "gameId required"); return getCounts(gameId); }