using System.Text;
using System.Text.Json;
using Microsoft.AspNetCore.Http.Extensions;

namespace Prospect.Server.Api.Middleware;

public class RequestLoggerMiddleware
{
    private readonly ILogger<RequestLoggerMiddleware> _logger;
    private readonly RequestDelegate _next;

    // Keywords used to surface social/squad/invite traffic while reverse-engineering the
    // squad-invite flow (see SQUAD-EMULATION.md). Matched against the path AND the body
    // (the CloudScript function name lives in the body of /Client/ExecuteFunction).
    private static readonly string[] SocialKeywords =
    {
        "group", "party", "lobby", "squad", "invite", "friend", "social", "matchmak",
    };

    public RequestLoggerMiddleware(ILogger<RequestLoggerMiddleware> logger, RequestDelegate next)
    {
        _logger = logger;
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        var body = await RequestAsync(context.Request);

        if (context.Request.Method == "POST")
        {
            var requestId = "NULL";

            if (context.Request.Headers.TryGetValue("X-RequestID", out var requestIdValues))
            {
                requestId = requestIdValues.ToString();
            }

            _logger.LogDebug("URL {Url} RequestId {RequestId} Body {Body}", context.Request.GetDisplayUrl(), requestId, body);
        }

        await _next(context);

        // ── Capture pass (squad-invite RE, see SQUAD-EMULATION.md) ──────────────
        // Runs AFTER the pipeline so we know whether the request was actually routed.
        if (context.Request.Method == "POST")
        {
            var path = context.Request.Path.Value ?? "";
            var haystack = (path + " " + body).ToLowerInvariant();

            // Any POST that fell through to a 404 = an endpoint the emulator does NOT implement
            // (e.g. a native PlayFab /Group/CreateGroup or /Lobby/* the client tried to call).
            if (context.Response.StatusCode == 404)
            {
                _logger.LogWarning("[CAPTURE UNROUTED] {Method} {Url} -> 404 | Body {Body}",
                    context.Request.Method, context.Request.GetDisplayUrl(), body);
            }
            else if (SocialKeywords.Any(k => haystack.Contains(k)))
            {
                _logger.LogInformation("[CAPTURE SOCIAL] {Url} ({Status}) | Body {Body}",
                    context.Request.GetDisplayUrl(), context.Response.StatusCode, body);
            }
        }
    }

    private static async Task<string> RequestAsync(HttpRequest request)
    {
        request.EnableBuffering();

        try
        {
            using (var reader = new StreamReader(request.Body, Encoding.UTF8, false, 4096, true))
            {
                var body = await reader.ReadToEndAsync();
                if (body.StartsWith("{"))
                {
                    var bodyJson = JsonSerializer.SerializeToUtf8Bytes(JsonSerializer.Deserialize<object>(body), new JsonSerializerOptions
                    {
                        WriteIndented = true
                    });

                    return Encoding.UTF8.GetString(bodyJson);
                }

                return body;
            }
        }
        finally
        {
            request.Body.Position = 0;
        }
    }
}