import { describe, expect, it } from "vitest"; import { buildParticipantSettlement, deriveSuggestedMatchState } from "./match"; describe("deriveSuggestedMatchState", () => { it("aggregates point, game and set events into a suggested scoreboard", () => { const result = deriveSuggestedMatchState([ { eventIndex: 1, eventType: "point", source: "camera_a", winnerSlot: "player_a", confidence: 0.6, payload: { rallyCount: 4, isWinner: true } }, { eventIndex: 2, eventType: "point", source: "camera_b", winnerSlot: "player_a", confidence: 0.7, payload: { rallyCount: 7, isAce: true, firstServeIn: true, firstServeAttempt: true } }, { eventIndex: 3, eventType: "game", source: "camera_a", winnerSlot: "player_a", confidence: 0.65 }, { eventIndex: 4, eventType: "set", source: "camera_a", winnerSlot: "player_a", confidence: 0.8 }, ]); expect(result.score.sets.player_a).toBe(1); expect(result.score.games.player_a).toBe(1); expect(result.score.points.player_a).toBe(0); expect(result.score.winnerSlot).toBe("player_a"); expect(result.metrics.players.player_a.pointsWon).toBe(2); expect(result.metrics.players.player_a.aces).toBe(1); expect(result.metrics.players.player_a.firstServePct).toBe(100); expect(result.metrics.longestRally).toBe(7); expect(result.sourceCount).toBe(2); }); it("prefers later reviewed score snapshots while keeping metric snapshots", () => { const result = deriveSuggestedMatchState([ { eventIndex: 1, eventType: "score_suggestion", source: "system", confidence: 0.78, payload: { score: { sets: { player_a: 1, player_b: 0 }, games: { player_a: 6, player_b: 4 }, points: { player_a: 0, player_b: 0 }, }, metrics: { player_a: { winners: 14, pointsWon: 32 }, player_b: { winners: 10, pointsWon: 25 }, totalRallies: 18, }, }, }, { eventIndex: 2, eventType: "review_adjustment", source: "admin", confidence: 1, payload: { score: { sets: { player_a: 2, player_b: 0 }, games: { player_a: 12, player_b: 6 }, points: { player_a: 68, player_b: 53 }, winnerSlot: "player_a", }, }, }, ]); expect(result.score.sets.player_a).toBe(2); expect(result.score.games.player_b).toBe(6); expect(result.score.points.player_a).toBe(68); expect(result.score.winnerSlot).toBe("player_a"); expect(result.metrics.players.player_a.winners).toBe(14); expect(result.metrics.totalRallies).toBe(18); }); }); describe("buildParticipantSettlement", () => { it("projects scoreboard and metrics into per-player settlement rows", () => { const settlement = buildParticipantSettlement( { sets: { player_a: 2, player_b: 1 }, games: { player_a: 13, player_b: 11 }, points: { player_a: 74, player_b: 68 }, winnerSlot: "player_a", }, { players: { player_a: { aces: 6, firstServeIn: 32, firstServeAttempts: 40, pointsWon: 74 }, player_b: { aces: 4, firstServeIn: 28, firstServeAttempts: 41, pointsWon: 68 }, }, totalRallies: 22, longestRally: 11, }, ); expect(settlement.winnerSlot).toBe("player_a"); expect(settlement.players.player_a.isWinner).toBe(true); expect(settlement.players.player_a.gamesWon).toBe(13); expect(settlement.players.player_a.stats.firstServePct).toBe(80); expect(settlement.players.player_b.stats.firstServePct).toBeCloseTo(68.3, 1); expect(settlement.summary.longestRally).toBe(11); }); });