using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Options;
using StellaOps.Vexer.Attestation.Extensions;
using StellaOps.Vexer.Attestation;
using StellaOps.Vexer.Attestation.Transparency;
using StellaOps.Vexer.ArtifactStores.S3.Extensions;
using StellaOps.Vexer.Export;
using StellaOps.Vexer.Storage.Mongo;

var builder = WebApplication.CreateBuilder(args);
var configuration = builder.Configuration;
var services = builder.Services;

services.AddOptions<VexMongoStorageOptions>()
    .Bind(configuration.GetSection("Vexer:Storage:Mongo"))
    .ValidateOnStart();

services.AddVexerMongoStorage();
services.AddVexExportEngine();
services.AddVexExportCacheServices();
services.AddVexAttestation();
services.Configure<VexAttestationClientOptions>(configuration.GetSection("Vexer:Attestation:Client"));

var rekorSection = configuration.GetSection("Vexer:Attestation:Rekor");
if (rekorSection.Exists())
{
    services.AddVexRekorClient(opts => rekorSection.Bind(opts));
}

var fileSystemSection = configuration.GetSection("Vexer:Artifacts:FileSystem");
if (fileSystemSection.Exists())
{
    services.AddVexFileSystemArtifactStore(opts => fileSystemSection.Bind(opts));
}
else
{
    services.AddVexFileSystemArtifactStore(_ => { });
}

var s3Section = configuration.GetSection("Vexer:Artifacts:S3");
if (s3Section.Exists())
{
    services.AddVexS3ArtifactClient(opts => s3Section.GetSection("Client").Bind(opts));
    services.AddSingleton<IVexArtifactStore, S3ArtifactStore>(provider =>
    {
        var options = new S3ArtifactStoreOptions();
        s3Section.GetSection("Store").Bind(options);
        return new S3ArtifactStore(
            provider.GetRequiredService<IS3ArtifactClient>(),
            Microsoft.Extensions.Options.Options.Create(options),
            provider.GetRequiredService<Microsoft.Extensions.Logging.ILogger<S3ArtifactStore>>());
    });
}

var offlineSection = configuration.GetSection("Vexer:Artifacts:OfflineBundle");
if (offlineSection.Exists())
{
    services.AddVexOfflineBundleArtifactStore(opts => offlineSection.Bind(opts));
}

services.AddEndpointsApiExplorer();
services.AddHealthChecks();
services.AddSingleton(TimeProvider.System);

var app = builder.Build();

app.MapGet("/vexer/status", async (HttpContext context,
    IEnumerable<IVexArtifactStore> artifactStores,
    IOptions<VexMongoStorageOptions> mongoOptions,
    TimeProvider timeProvider) =>
{
    var payload = new StatusResponse(
        timeProvider.GetUtcNow(),
        mongoOptions.Value.RawBucketName,
        mongoOptions.Value.GridFsInlineThresholdBytes,
        artifactStores.Select(store => store.GetType().Name).ToArray());

    context.Response.ContentType = "application/json";
    await System.Text.Json.JsonSerializer.SerializeAsync(context.Response.Body, payload);
});

app.MapHealthChecks("/vexer/health");

app.Run();

public partial class Program;

internal sealed record StatusResponse(DateTimeOffset UtcNow, string MongoBucket, int InlineThreshold, string[] ArtifactStores);
