using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using StellaOps.Vexer.Core;
using StellaOps.Vexer.Storage.Mongo;

namespace StellaOps.Vexer.Export;

public interface IVexExportCacheService
{
    ValueTask InvalidateAsync(VexQuerySignature signature, VexExportFormat format, CancellationToken cancellationToken);

    ValueTask<int> PruneExpiredAsync(DateTimeOffset asOf, CancellationToken cancellationToken);

    ValueTask<int> PruneDanglingAsync(CancellationToken cancellationToken);
}

internal sealed class VexExportCacheService : IVexExportCacheService
{
    private readonly IVexCacheIndex _cacheIndex;
    private readonly IVexCacheMaintenance _maintenance;
    private readonly ILogger<VexExportCacheService> _logger;

    public VexExportCacheService(
        IVexCacheIndex cacheIndex,
        IVexCacheMaintenance maintenance,
        ILogger<VexExportCacheService> logger)
    {
        _cacheIndex = cacheIndex ?? throw new ArgumentNullException(nameof(cacheIndex));
        _maintenance = maintenance ?? throw new ArgumentNullException(nameof(maintenance));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    public async ValueTask InvalidateAsync(VexQuerySignature signature, VexExportFormat format, CancellationToken cancellationToken)
    {
        ArgumentNullException.ThrowIfNull(signature);
        await _cacheIndex.RemoveAsync(signature, format, cancellationToken).ConfigureAwait(false);
        _logger.LogInformation("Invalidated export cache entry {Signature} ({Format})", signature.Value, format);
    }

    public ValueTask<int> PruneExpiredAsync(DateTimeOffset asOf, CancellationToken cancellationToken)
        => _maintenance.RemoveExpiredAsync(asOf, cancellationToken);

    public ValueTask<int> PruneDanglingAsync(CancellationToken cancellationToken)
        => _maintenance.RemoveMissingManifestReferencesAsync(cancellationToken);
}

public static class VexExportCacheServiceCollectionExtensions
{
    public static IServiceCollection AddVexExportCacheServices(this IServiceCollection services)
    {
        services.AddSingleton<IVexExportCacheService, VexExportCacheService>();
        return services;
    }
}
