using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Net.Http.Json;
using System.IO;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Mongo2Go;
using MongoDB.Driver;
using StellaOps.Vexer.Attestation.Signing;
using StellaOps.Vexer.Policy;
using StellaOps.Vexer.Core;
using StellaOps.Vexer.Export;
using StellaOps.Vexer.WebService;

namespace StellaOps.Vexer.WebService.Tests;

public sealed class StatusEndpointTests : IClassFixture<WebApplicationFactory<Program>>, IDisposable
{
    private readonly WebApplicationFactory<Program> _factory;
    private readonly MongoDbRunner _runner;

    public StatusEndpointTests(WebApplicationFactory<Program> factory)
    {
        _runner = MongoDbRunner.Start();
        _factory = factory.WithWebHostBuilder(builder =>
        {
            builder.ConfigureAppConfiguration((_, config) =>
            {
                var rootPath = Path.Combine(Path.GetTempPath(), "vexer-offline-tests");
                Directory.CreateDirectory(rootPath);
                var settings = new Dictionary<string, string?>
                {
                    ["Vexer:Storage:Mongo:RawBucketName"] = "vex.raw",
                    ["Vexer:Storage:Mongo:GridFsInlineThresholdBytes"] = "256",
                    ["Vexer:Artifacts:FileSystem:RootPath"] = rootPath,
                };
                config.AddInMemoryCollection(settings!);
            });

            builder.ConfigureServices(services =>
            {
                services.AddSingleton<IMongoClient>(_ => new MongoClient(_runner.ConnectionString));
                services.AddSingleton(provider => provider.GetRequiredService<IMongoClient>().GetDatabase("vexer-web-tests"));
                services.AddSingleton<IVexSigner, FakeSigner>();
                services.AddSingleton<IVexPolicyEvaluator, FakePolicyEvaluator>();
                services.AddSingleton<IVexExportDataSource, FakeExportDataSource>();
            });
        });
    }

    [Fact]
    public async Task StatusEndpoint_ReturnsArtifactStores()
    {
        var client = _factory.CreateClient();
        var response = await client.GetAsync("/vexer/status");
        var raw = await response.Content.ReadAsStringAsync();
        Assert.True(response.IsSuccessStatusCode, raw);

        var payload = System.Text.Json.JsonSerializer.Deserialize<StatusResponse>(raw);
        Assert.NotNull(payload);
        Assert.NotEmpty(payload!.ArtifactStores);
    }

    public void Dispose()
    {
        _runner.Dispose();
    }

    private sealed class StatusResponse
    {
        public string[] ArtifactStores { get; set; } = Array.Empty<string>();
    }

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

    private sealed class FakePolicyEvaluator : IVexPolicyEvaluator
    {
        public string Version => "test";

        public VexPolicySnapshot Snapshot => VexPolicySnapshot.Default;

        public double GetProviderWeight(VexProvider provider) => 1.0;

        public bool IsClaimEligible(VexClaim claim, VexProvider provider, out string? rejectionReason)
        {
            rejectionReason = null;
            return true;
        }
    }

    private sealed class FakeExportDataSource : IVexExportDataSource
    {
        public ValueTask<VexExportDataSet> FetchAsync(VexQuery query, CancellationToken cancellationToken)
        {
            var dataset = new VexExportDataSet(ImmutableArray<VexConsensus>.Empty, ImmutableArray<VexClaim>.Empty, ImmutableArray<string>.Empty);
            return ValueTask.FromResult(dataset);
        }
    }
}
