using NeonSprawl.Server.Game.PositionState; namespace NeonSprawl.Server.Game.Factions; /// Maps GET /game/players/{{id}}/faction-standing — read snapshot (NEO-139). public static class FactionStandingApi { public static WebApplication MapFactionStandingApi(this WebApplication app) { app.MapGet( "/game/players/{id}/faction-standing", (string id, IPositionStateStore positions, IFactionDefinitionRegistry factionRegistry, IFactionStandingStore standingStore) => { var trimmedId = id.Trim(); if (trimmedId.Length == 0 || !positions.TryGetPosition(trimmedId, out _)) { return Results.NotFound(); } var snapshotResult = TryBuildSnapshot(trimmedId, factionRegistry, standingStore); return snapshotResult.Kind switch { FactionStandingSnapshotBuildKind.Success => Results.Json(snapshotResult.Response), FactionStandingSnapshotBuildKind.StoreReadFailed => Results.Problem( statusCode: StatusCodes.Status500InternalServerError, title: "Faction standing read failed", detail: snapshotResult.ReasonCode), _ => throw new InvalidOperationException($"Unexpected build outcome: {snapshotResult.Kind}"), }; }); return app; } internal static FactionStandingSnapshotResponse BuildSnapshot( string playerId, IFactionDefinitionRegistry factionRegistry, IFactionStandingStore standingStore) { var result = TryBuildSnapshot(playerId, factionRegistry, standingStore); if (result.Kind != FactionStandingSnapshotBuildKind.Success || result.Response is null) { throw new InvalidOperationException( $"BuildSnapshot failed: {result.ReasonCode ?? result.Kind.ToString()}"); } return result.Response; } private static FactionStandingSnapshotBuildResult TryBuildSnapshot( string playerId, IFactionDefinitionRegistry factionRegistry, IFactionStandingStore standingStore) { var defs = factionRegistry.GetDefinitionsInIdOrder(); var factions = new List(defs.Count); foreach (var definition in defs) { var outcome = standingStore.TryGetStanding(playerId, definition.Id); if (!outcome.Success) { return new FactionStandingSnapshotBuildResult( FactionStandingSnapshotBuildKind.StoreReadFailed, null, outcome.ReasonCode); } factions.Add( new FactionStandingRowJson { Id = definition.Id, Standing = outcome.Standing, }); } return new FactionStandingSnapshotBuildResult( FactionStandingSnapshotBuildKind.Success, new FactionStandingSnapshotResponse { PlayerId = playerId, Factions = factions, SchemaVersion = FactionStandingSnapshotResponse.CurrentSchemaVersion, }, null); } private enum FactionStandingSnapshotBuildKind { Success, StoreReadFailed, } private readonly record struct FactionStandingSnapshotBuildResult( FactionStandingSnapshotBuildKind Kind, FactionStandingSnapshotResponse? Response, string? ReasonCode); }