import { calculatePickPoints } from "~/models/scoring-rules"; export type CoronaState = | { type: "eliminated"; points: 0 } | { type: "pending" } | { type: "scored"; brightness: number; points: number }; interface PickEntry { participant: { id: string; sportsSeasonId: string }; scoringPattern: string | null; } interface ResultEntry { participantId: string; finalPosition: number | null; isPartialScore: boolean | null; } interface ScoringRules { pointsFor1st: number; pointsFor2nd: number; pointsFor3rd: number; pointsFor4th: number; pointsFor5th: number; pointsFor6th: number; pointsFor7th: number; pointsFor8th: number; } /** * Corona badge state for every pick on the draft board. * * @param sharedPlacementCountsBySportsSeason - sportsSeasonId → (finalPosition → * how many participants share it), from getSharedPlacementCounts. Required for * qualifying_points picks: a golfer tied for 8th earns the split award, and * omitting this would show him at full value here while the standings show the * split — the exact inconsistency this parameter exists to prevent. */ export function computeCoronaStates( picks: PickEntry[], resultByParticipant: Map, bracketTemplateBySportsSeason: Map, scoringRules: ScoringRules, maxPoints: number, sharedPlacementCountsBySportsSeason: Map>, ): Record { const coronaStates: Record = {}; for (const pick of picks) { const result = resultByParticipant.get(pick.participant.id); if (!result || result.finalPosition === null) { coronaStates[pick.participant.id] = { type: "pending" }; continue; } if (result.finalPosition === 0 && !result.isPartialScore) { coronaStates[pick.participant.id] = { type: "eliminated", points: 0 }; continue; } if (result.finalPosition > 0) { const points = calculatePickPoints( result.finalPosition, pick.scoringPattern, scoringRules, { bracketTemplateId: bracketTemplateBySportsSeason.get(pick.participant.sportsSeasonId) ?? null, tiedParticipants: sharedPlacementCountsBySportsSeason .get(pick.participant.sportsSeasonId) ?.get(result.finalPosition) ?? 1, } ); const brightness = maxPoints > 0 ? Math.min(points / maxPoints, 1) : 0; coronaStates[pick.participant.id] = { type: "scored", brightness, points }; continue; } coronaStates[pick.participant.id] = { type: "pending" }; } return coronaStates; }