import { clampDiceCount, createInitialDiceRollState, formatDiceNotation, isDiceSides, rollDiceValues, type DiceRollEvent, type DiceRollState, } from '../../shared/types/diceRoll'; export class DiceRollSessionStore { private state: DiceRollState = createInitialDiceRollState(); getState(): DiceRollState { return this.state; } clear(): DiceRollState { this.state = createInitialDiceRollState(); return this.state; } dispatch(event: DiceRollEvent): DiceRollState { switch (event.kind) { case 'clear': { if (!this.state.active && this.state.values.length === 0) return this.state; this.state = { ...createInitialDiceRollState(), revision: this.state.revision + 1, visibleToPlayers: this.state.visibleToPlayers, }; return this.state; } case 'setVisibleToPlayers': { if (this.state.visibleToPlayers === event.visible) return this.state; this.state = { ...this.state, revision: this.state.revision + 1, visibleToPlayers: event.visible, ...(event.visible === false && this.state.active ? { active: false, startedAt: null } : {}), }; return this.state; } case 'hideOverlay': { if (!this.state.active) return this.state; this.state = { ...this.state, revision: this.state.revision + 1, active: false, startedAt: null, }; return this.state; } case 'roll': { if (!isDiceSides(event.sides)) return this.state; const count = clampDiceCount(event.count); if (count < 1) return this.state; const values = rollDiceValues(count, event.sides); const total = values.reduce((a, b) => a + b, 0); const showToPlayers = this.state.visibleToPlayers; this.state = { revision: this.state.revision + 1, active: showToPlayers, visibleToPlayers: showToPlayers, notation: formatDiceNotation(count, event.sides), values, total, startedAt: showToPlayers ? Date.now() : null, }; return this.state; } default: { const _exhaustive: never = event; return _exhaustive; } } } }