using RpgRoller.Contracts;
using RpgRoller.Services;

namespace RpgRoller.Api;

internal static class StateEventEndpoints
{
    public static RouteGroupBuilder MapStateEventEndpoints(this RouteGroupBuilder group)
    {
        group.MapGet("/events/state", async Task<IResult> (Guid campaignId, HttpContext context, IGameService game) =>
        {
            var sessionToken = context.GetRequiredSessionToken();
            var stateResult = game.GetCampaignStateSnapshot(sessionToken, campaignId);
            if (!stateResult.Succeeded)
                return stateResult.Error!.Code == "unauthorized" ? TypedResults.Unauthorized() : TypedResults.BadRequest(new ApiError(stateResult.Error.Message, stateResult.Error.Code));

            context.Response.Headers.CacheControl = "no-cache";
            context.Response.Headers.Connection = "keep-alive";
            context.Response.ContentType = "text/event-stream";

            var lastState = stateResult.Value!;
            await WriteStateEventAsync(context.Response, lastState);
            await context.Response.Body.FlushAsync();

            try
            {
                while (!context.RequestAborted.IsCancellationRequested)
                {
                    await Task.Delay(TimeSpan.FromSeconds(1), context.RequestAborted);

                    var currentStateResult = game.GetCampaignStateSnapshot(sessionToken, campaignId);
                    if (!currentStateResult.Succeeded)
                        break;

                    var currentState = currentStateResult.Value!;
                    if (currentState.TotalVersion != lastState.TotalVersion)
                    {
                        lastState = currentState;
                        await WriteStateEventAsync(context.Response, currentState);
                    }
                    else
                        await context.Response.WriteAsync(": heartbeat\n\n");

                    await context.Response.Body.FlushAsync();
                }
            }
            catch (OperationCanceledException)
            {
            }

            return TypedResults.Empty;
        });

        return group;
    }

    private static Task WriteStateEventAsync(HttpResponse response, CampaignStateSnapshot snapshot)
    {
        var characterVersions = string.Join(",", snapshot.CharacterVersions.Select(version => $"{{\"characterId\":\"{version.CharacterId}\",\"version\":{version.Version}}}"));

        return response.WriteAsync($"event: state\ndata: {{\"campaignId\":\"{snapshot.CampaignId}\",\"totalVersion\":{snapshot.TotalVersion},\"rosterVersion\":{snapshot.RosterVersion},\"logVersion\":{snapshot.LogVersion},\"characterVersions\":[{characterVersions}]}}\n\n");
    }
}