using FluentAssertions;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging.Abstractions;
using StellaOps.Excititor.Connectors.OCI.OpenVEX.Attest.Configuration;
using StellaOps.Excititor.Connectors.OCI.OpenVEX.Attest.Discovery;
using System.Collections.Generic;
using System.IO.Abstractions.TestingHelpers;
using Xunit;

namespace StellaOps.Excititor.Connectors.OCI.OpenVEX.Attest.Tests.Discovery;

public sealed class OciAttestationDiscoveryServiceTests
{
    [Fact]
    public async Task LoadAsync_ResolvesOfflinePaths()
    {
        var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
        {
            ["/bundles/registry.example.com/repo/image/latest/openvex-attestations.tgz"] = new MockFileData(string.Empty),
        });

        using var cache = new MemoryCache(new MemoryCacheOptions());
        var service = new OciAttestationDiscoveryService(cache, fileSystem, NullLogger<OciAttestationDiscoveryService>.Instance);

        var options = new OciOpenVexAttestationConnectorOptions
        {
            AllowHttpRegistries = true,
        };

        options.Images.Add(new OciImageSubscriptionOptions
        {
            Reference = "registry.example.com/repo/image:latest",
        });

        options.Offline.RootDirectory = "/bundles";
        options.Cosign.Mode = CosignCredentialMode.None;

        var result = await service.LoadAsync(options, CancellationToken.None);

        result.Targets.Should().ContainSingle();
        result.Targets[0].OfflineBundle.Should().NotBeNull();
        var offline = result.Targets[0].OfflineBundle!;
        offline.Exists.Should().BeTrue();
        var expectedPath = fileSystem.Path.Combine(
            fileSystem.Path.GetFullPath("/bundles"),
            "registry.example.com",
            "repo",
            "image",
            "latest",
            "openvex-attestations.tgz");
        offline.Path.Should().Be(expectedPath);
    }

    [Fact]
    public async Task LoadAsync_CachesResults()
    {
        var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
        {
            ["/bundles/registry.example.com/repo/image/latest/openvex-attestations.tgz"] = new MockFileData(string.Empty),
        });

        using var cache = new MemoryCache(new MemoryCacheOptions());
        var service = new OciAttestationDiscoveryService(cache, fileSystem, NullLogger<OciAttestationDiscoveryService>.Instance);

        var options = new OciOpenVexAttestationConnectorOptions
        {
            AllowHttpRegistries = true,
        };

        options.Images.Add(new OciImageSubscriptionOptions
        {
            Reference = "registry.example.com/repo/image:latest",
        });

        options.Offline.RootDirectory = "/bundles";
        options.Cosign.Mode = CosignCredentialMode.None;

        var first = await service.LoadAsync(options, CancellationToken.None);
        var second = await service.LoadAsync(options, CancellationToken.None);

        ReferenceEquals(first, second).Should().BeTrue();
    }
}
