using System.Collections.Immutable;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using StellaOps.Vexer.Attestation.Dsse;
using StellaOps.Vexer.Attestation.Signing;
using StellaOps.Vexer.Attestation.Transparency;
using StellaOps.Vexer.Core;

namespace StellaOps.Vexer.Attestation.Tests;

public sealed class VexAttestationClientTests
{
    [Fact]
    public async Task SignAsync_ReturnsEnvelopeDigestAndDiagnostics()
    {
        var signer = new FakeSigner();
        var builder = new VexDsseBuilder(signer, NullLogger<VexDsseBuilder>.Instance);
        var options = Options.Create(new VexAttestationClientOptions());
        var client = new VexAttestationClient(builder, options, NullLogger<VexAttestationClient>.Instance);

        var request = new VexAttestationRequest(
            ExportId: "exports/456",
            QuerySignature: new VexQuerySignature("filters"),
            Artifact: new VexContentAddress("sha256", "deadbeef"),
            Format: VexExportFormat.Json,
            CreatedAt: DateTimeOffset.UtcNow,
            SourceProviders: ImmutableArray.Create("vendor"),
            Metadata: ImmutableDictionary<string, string>.Empty);

        var response = await client.SignAsync(request, CancellationToken.None);

        Assert.NotNull(response.Attestation);
        Assert.NotNull(response.Attestation.EnvelopeDigest);
        Assert.True(response.Diagnostics.ContainsKey("envelope"));
    }

    [Fact]
    public async Task SignAsync_SubmitsToTransparencyLog_WhenConfigured()
    {
        var signer = new FakeSigner();
        var builder = new VexDsseBuilder(signer, NullLogger<VexDsseBuilder>.Instance);
        var options = Options.Create(new VexAttestationClientOptions());
        var transparency = new FakeTransparencyLogClient();
        var client = new VexAttestationClient(builder, options, NullLogger<VexAttestationClient>.Instance, transparencyLogClient: transparency);

        var request = new VexAttestationRequest(
            ExportId: "exports/789",
            QuerySignature: new VexQuerySignature("filters"),
            Artifact: new VexContentAddress("sha256", "deadbeef"),
            Format: VexExportFormat.Json,
            CreatedAt: DateTimeOffset.UtcNow,
            SourceProviders: ImmutableArray.Create("vendor"),
            Metadata: ImmutableDictionary<string, string>.Empty);

        var response = await client.SignAsync(request, CancellationToken.None);

        Assert.NotNull(response.Attestation.Rekor);
        Assert.True(response.Diagnostics.ContainsKey("rekorLocation"));
        Assert.True(transparency.SubmitCalled);
    }

    private sealed class FakeSigner : IVexSigner
    {
        public ValueTask<VexSignedPayload> SignAsync(ReadOnlyMemory<byte> payload, CancellationToken cancellationToken)
            => ValueTask.FromResult(new VexSignedPayload("signature", "key"));
    }

    private sealed class FakeTransparencyLogClient : ITransparencyLogClient
    {
        public bool SubmitCalled { get; private set; }

        public ValueTask<TransparencyLogEntry> SubmitAsync(DsseEnvelope envelope, CancellationToken cancellationToken)
        {
            SubmitCalled = true;
            return ValueTask.FromResult(new TransparencyLogEntry(Guid.NewGuid().ToString(), "https://rekor.example/entries/123", "23", null));
        }

        public ValueTask<bool> VerifyAsync(string entryLocation, CancellationToken cancellationToken)
            => ValueTask.FromResult(true);
    }
}
