using System;
using System.Net;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using StellaOps.Scanner.Sbomer.BuildXPlugin;
using StellaOps.Scanner.Sbomer.BuildXPlugin.Attestation;
using StellaOps.Scanner.Sbomer.BuildXPlugin.Descriptor;
using Xunit;

namespace StellaOps.Scanner.Sbomer.BuildXPlugin.Tests.Attestation;

public sealed class AttestorClientTests
{
    [Fact]
    public async Task SendPlaceholderAsync_PostsJsonPayload()
    {
        var handler = new RecordingHandler(new HttpResponseMessage(HttpStatusCode.Accepted));
        using var httpClient = new HttpClient(handler);
        var client = new AttestorClient(httpClient);

        var document = BuildDescriptorDocument();
        var attestorUri = new Uri("https://attestor.example.com/api/v1/provenance");

        await client.SendPlaceholderAsync(attestorUri, document, CancellationToken.None);

        Assert.NotNull(handler.CapturedRequest);
        Assert.Equal(HttpMethod.Post, handler.CapturedRequest!.Method);
        Assert.Equal(attestorUri, handler.CapturedRequest.RequestUri);

        var content = await handler.CapturedRequest.Content!.ReadAsStringAsync();
        var json = JsonDocument.Parse(content);
        Assert.Equal(document.Subject.Digest, json.RootElement.GetProperty("imageDigest").GetString());
        Assert.Equal(document.Artifact.Digest, json.RootElement.GetProperty("sbomDigest").GetString());
        Assert.Equal(document.Provenance.ExpectedDsseSha256, json.RootElement.GetProperty("expectedDsseSha256").GetString());
    }

    [Fact]
    public async Task SendPlaceholderAsync_ThrowsOnFailure()
    {
        var handler = new RecordingHandler(new HttpResponseMessage(HttpStatusCode.BadRequest)
        {
            Content = new StringContent("invalid")
        });
        using var httpClient = new HttpClient(handler);
        var client = new AttestorClient(httpClient);

        var document = BuildDescriptorDocument();
        var attestorUri = new Uri("https://attestor.example.com/api/v1/provenance");

        await Assert.ThrowsAsync<BuildxPluginException>(() => client.SendPlaceholderAsync(attestorUri, document, CancellationToken.None));
    }

    private static DescriptorDocument BuildDescriptorDocument()
    {
        var subject = new DescriptorSubject("application/vnd.oci.image.manifest.v1+json", "sha256:img");
        var artifact = new DescriptorArtifact("application/vnd.cyclonedx+json", "sha256:sbom", 42, new System.Collections.Generic.Dictionary<string, string>());
        var provenance = new DescriptorProvenance("pending", "sha256:dsse", "nonce", "https://attestor.example.com/api/v1/provenance", "https://slsa.dev/provenance/v1");
        var generatorMetadata = new DescriptorGeneratorMetadata("generator", "1.0.0");
        var metadata = new System.Collections.Generic.Dictionary<string, string>();
        return new DescriptorDocument("schema", DateTimeOffset.UtcNow, generatorMetadata, subject, artifact, provenance, metadata);
    }

    private sealed class RecordingHandler : HttpMessageHandler
    {
        private readonly HttpResponseMessage response;

        public RecordingHandler(HttpResponseMessage response)
        {
            this.response = response;
        }

        public HttpRequestMessage? CapturedRequest { get; private set; }

        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            CapturedRequest = request;
            return Task.FromResult(response);
        }
    }
}
