using GameList.Contracts; using GameList.Data; using GameList.Domain; using Microsoft.EntityFrameworkCore; using Microsoft.AspNetCore.Mvc; namespace GameList.Endpoints; public static class StateEndpoints { public static void MapStateEndpoints(this IEndpointRouteBuilder app) { app.MapGet("/api/state", async (HttpContext ctx, AppDbContext db) => { var player = await EndpointHelpers.GetAuthenticatedPlayer(ctx, db); if (player is null) return Results.Unauthorized(); var state = await db.AppState.AsNoTracking().FirstAsync(); var summary = new { CurrentPhase = player.CurrentPhase, state.ResultsOpen, state.UpdatedAt, Players = await db.Players.CountAsync(), Suggestions = await db.Suggestions.CountAsync(), Votes = await db.Votes.CountAsync() }; return Results.Ok(summary); }); app.MapGet("/api/me", async (HttpContext ctx, AppDbContext db) => { var player = await EndpointHelpers.GetAuthenticatedPlayer(ctx, db); if (player is null) return Results.Unauthorized(); return Results.Ok(new { player.Id, player.DisplayName, player.Username, player.IsAdmin, player.CurrentPhase }); }); app.MapPost("/api/me/phase/next", async (HttpContext ctx, AppDbContext db) => { var player = await EndpointHelpers.GetAuthenticatedPlayer(ctx, db); if (player is null) return Results.Unauthorized(); var next = NextPhase(player.CurrentPhase); var appState = await db.AppState.FirstAsync(); if (next == Phase.Results && !appState.ResultsOpen) { return Results.BadRequest(new { error = "Results are locked until the admin enables them." }); } player.CurrentPhase = next; await db.SaveChangesAsync(); return Results.Ok(new { player.CurrentPhase, appState.ResultsOpen }); }); app.MapPost("/api/me/phase/prev", async (HttpContext ctx, AppDbContext db) => { var player = await EndpointHelpers.GetAuthenticatedPlayer(ctx, db); if (player is null) return Results.Unauthorized(); player.CurrentPhase = PrevPhase(player.CurrentPhase); await db.SaveChangesAsync(); var appState = await db.AppState.AsNoTracking().FirstAsync(); return Results.Ok(new { player.CurrentPhase, appState.ResultsOpen }); }); app.MapPost("/api/me/name", async ([FromBody] SetNameRequest request, HttpContext ctx, AppDbContext db) => { var name = EndpointHelpers.TrimTo(request.Name, 16); if (string.IsNullOrWhiteSpace(name)) { return Results.BadRequest(new { error = "Name is required and must be <= 16 characters." }); } var player = await EndpointHelpers.GetAuthenticatedPlayer(ctx, db); if (player is null) return Results.Unauthorized(); player.DisplayName = name; await db.SaveChangesAsync(); return Results.Ok(new { player.Id, player.DisplayName }); }); } private static Phase NextPhase(Phase current) => current switch { Phase.Suggest => Phase.Reveal, Phase.Reveal => Phase.Vote, Phase.Vote => Phase.Results, _ => Phase.Results }; private static Phase PrevPhase(Phase current) => current switch { Phase.Results => Phase.Vote, Phase.Vote => Phase.Reveal, Phase.Reveal => Phase.Suggest, _ => Phase.Suggest }; }