using GameList.Contracts; using GameList.Data; using GameList.Domain; using Microsoft.EntityFrameworkCore; namespace GameList.Endpoints; internal sealed class StateWorkflowService(AppDbContext db) { public async Task> GetStateAsync(Player player) { var state = await db.AppState.AsNoTracking().SingleAsync(); var phase = EndpointHelpers.GetCurrentPhase(player.CurrentPhase, state.ResultsOpen); var summary = new StateSummaryResponse(phase, player.VotesFinal, player.HasJoker, state.ResultsOpen, state.UpdatedAt, await db.Players.CountAsync(), await db.Suggestions.CountAsync(), await db.Votes.CountAsync()); return ServiceResult.Success(summary); } public async Task> GetMeAsync(Player player) { var state = await db.AppState.AsNoTracking().SingleAsync(); var phase = EndpointHelpers.GetCurrentPhase(player.CurrentPhase, state.ResultsOpen); return ServiceResult.Success(new MeResponse(player.Id, player.Username, player.DisplayName, player.IsAdmin, player.IsOwner, phase, player.VotesFinal, player.HasJoker)); } public async Task> NextPhaseAsync(Player player) { var appState = await db.AppState.SingleAsync(); var shouldSave = EndpointHelpers.ReconcilePlayerPhase(player, appState.ResultsOpen); try { var next = NextPhase(player.CurrentPhase); if (next == Phase.Vote) { var hasSuggestions = await db.Suggestions.AnyAsync(s => s.PlayerId == player.Id); if (!hasSuggestions) return ServiceResult.Failure(ServiceError.BadRequest("Add at least one suggestion before entering the Vote phase.")); } if (next == Phase.Results && !appState.ResultsOpen) return ServiceResult.Failure(ServiceError.BadRequest("Results are locked until the admin enables them.")); player.CurrentPhase = next; player.VotesFinal = false; // moving forward clears any prior finalize shouldSave = true; return ServiceResult.Success(new PhaseTransitionResponse(player.CurrentPhase, appState.ResultsOpen)); } finally { if (shouldSave) await db.SaveChangesAsync(); } } public async Task> PrevPhaseAsync(Player player) { if (!player.IsAdmin) return ServiceResult.Failure(ServiceError.BadRequest("Only admins can move backward.")); var appState = await db.AppState.SingleAsync(); _ = EndpointHelpers.ReconcilePlayerPhase(player, appState.ResultsOpen); player.CurrentPhase = PrevPhase(player.CurrentPhase); player.VotesFinal = false; await db.SaveChangesAsync(); return ServiceResult.Success(new PhaseTransitionResponse(player.CurrentPhase, appState.ResultsOpen)); } private static Phase NextPhase(Phase current) => current switch { Phase.Suggest => Phase.Vote, _ => Phase.Results }; private static Phase PrevPhase(Phase current) => current switch { Phase.Results => Phase.Vote, _ => Phase.Suggest }; }