using GameList.Contracts; using GameList.Data; using GameList.Domain; using Microsoft.EntityFrameworkCore; namespace GameList.Endpoints; internal sealed class VoteWorkflowService(AppDbContext db) { public async Task GetMineAsync(Player player) { var phase = await EndpointHelpers.GetCurrentPhaseAsync(db, player.Id); if (phase != Phase.Vote) return EndpointHelpers.PhaseMismatch(Phase.Vote, phase); var votes = await db.Votes .AsNoTracking() .Where(v => v.PlayerId == player.Id) .Select(v => new { v.SuggestionId, v.Score }) .ToListAsync(); return Results.Ok(votes); } public async Task UpsertAsync(Player player, VoteRequest request) { if (request.Score is < 0 or > 10) return Results.BadRequest(new { error = "Score must be between 0 and 10." }); if (player.VotesFinal) return Results.BadRequest(new { error = "Votes are finalized. Unfinalize before changing scores." }); var phase = await EndpointHelpers.GetCurrentPhaseAsync(db, player.Id); if (phase != Phase.Vote) return EndpointHelpers.PhaseMismatch(Phase.Vote, phase); if (string.IsNullOrWhiteSpace(player.DisplayName)) return Results.BadRequest(new { error = "Set a display name before voting." }); var linkMap = await db.Suggestions .AsNoTracking() .Select(s => new { s.Id, s.ParentSuggestionId }) .ToListAsync(); var rootIndex = EndpointHelpers.BuildLinkRoots(linkMap.Select(s => (s.Id, s.ParentSuggestionId))); if (!rootIndex.ContainsKey(request.SuggestionId)) return Results.BadRequest(new { error = "Suggestion not found." }); var linkedIds = EndpointHelpers.LinkedIdsFor(request.SuggestionId, rootIndex); if (linkedIds.Count == 0) linkedIds.Add(request.SuggestionId); var existingVotes = await db.Votes .Where(v => v.PlayerId == player.Id && linkedIds.Contains(v.SuggestionId)) .ToListAsync(); foreach (var suggestionId in linkedIds) { var vote = existingVotes.FirstOrDefault(v => v.SuggestionId == suggestionId); if (vote == null) { db.Votes.Add(new Vote { PlayerId = player.Id, SuggestionId = suggestionId, Score = request.Score }); } else { vote.Score = request.Score; } } await db.SaveChangesAsync(); return Results.Ok(new { SuggestionIds = linkedIds, request.Score }); } public async Task SetFinalizeAsync(Player player, VoteFinalizeRequest request) { var phase = await EndpointHelpers.GetCurrentPhaseAsync(db, player.Id); if (phase != Phase.Vote) return EndpointHelpers.PhaseMismatch(Phase.Vote, phase); player.VotesFinal = request.Final; await db.SaveChangesAsync(); return Results.Ok(new { player.VotesFinal }); } }