using System.Text;
using ApiOPE.Configuration;
using ApiOPE.Contracts;
using ApiOPE.Security;
using ApiOPE.Services;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;

namespace ApiOPE.Tests;

public sealed class OpeProtocolTests
{
    [Fact]
    public void ResponseSigner_MatchesGestionaHexThenBase64Algorithm()
    {
        var signer = new OpeResponseSigner(Options.Create(new OpeOptions
        {
            SecretKey = "test-secret-key-with-more-than-32-characters"
        }));

        var signature = signer.Sign("26cd0da5-c45f-497d-b380-820c03cf3237");

        Assert.Equal(
            "MmE0MjEwM2Y1NTM2NjRkM2FmMzRhNDZlNmQxNjE0NzVmNmE0OTQxNDUxN2NlYmU2ODZjOTZiYzg5YmFjY2FmYw==",
            signature);
    }

    [Fact]
    public void ResponseSigner_PreservesUuidTextCasing()
    {
        var signer = new OpeResponseSigner(Options.Create(new OpeOptions
        {
            SecretKey = "test-secret-key-with-more-than-32-characters"
        }));

        Assert.NotEqual(
            signer.Sign("26cd0da5-c45f-497d-b380-820c03cf3237"),
            signer.Sign("26CD0DA5-C45F-497D-B380-820C03CF3237"));
    }

    [Fact]
    public async Task RequestReader_AcceptsVendorJsonMediaType()
    {
        var context = CreateHttpContext(
            "application/vnd.generic-operation-request+json; charset=utf-8",
            """
            {"data":{"FIELD_0":{"type":"STRING","value":"53/2026"}}}
            """);

        var result = await GenericOperationRequestReader.ReadAsync(
            context.Request,
            CancellationToken.None);

        Assert.True(result.IsValid);
        Assert.Equal("53/2026", result.Request!.Data["FIELD_0"].Value);
    }

    [Fact]
    public async Task RequestReader_ReturnsFieldErrorsForUnexpectedInput()
    {
        var context = CreateHttpContext(
            OpeMediaTypes.GenericOperationRequest,
            """
            {"data":{"FIELD_1":{"type":"STRING","value":"unexpected"}}}
            """);

        var result = await GenericOperationRequestReader.ReadAsync(
            context.Request,
            CancellationToken.None);

        Assert.False(result.IsValid);
        Assert.Equal(OpeFieldErrors.NotExpected, result.Errors["FIELD_1"]);
        Assert.Equal(OpeFieldErrors.Expected, result.Errors["FIELD_0"]);
    }

    private static DefaultHttpContext CreateHttpContext(string contentType, string body)
    {
        var context = new DefaultHttpContext();
        context.Request.ContentType = contentType;
        context.Request.Body = new MemoryStream(Encoding.UTF8.GetBytes(body));
        return context;
    }
}
