using System.Threading;
using System.Threading.Tasks;
using MongoDB.Driver;
using StellaOps.Vexer.Core;

namespace StellaOps.Vexer.Storage.Mongo;

public sealed class MongoVexExportStore : IVexExportStore
{
    private readonly IMongoCollection<VexExportManifestRecord> _collection;

    public MongoVexExportStore(IMongoDatabase database)
    {
        ArgumentNullException.ThrowIfNull(database);
        VexMongoMappingRegistry.Register();
        _collection = database.GetCollection<VexExportManifestRecord>(VexMongoCollectionNames.Exports);
        EnsureIndexes(_collection);
    }

    public async ValueTask<VexExportManifest?> FindAsync(VexQuerySignature signature, VexExportFormat format, CancellationToken cancellationToken)
    {
        ArgumentNullException.ThrowIfNull(signature);
        var id = VexExportManifestRecord.CreateId(signature, format);
        var filter = Builders<VexExportManifestRecord>.Filter.Eq(x => x.Id, id);
        var entity = await _collection.Find(filter).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
        return entity?.ToDomain();
    }

    public async ValueTask SaveAsync(VexExportManifest manifest, CancellationToken cancellationToken)
    {
        ArgumentNullException.ThrowIfNull(manifest);
        var entity = VexExportManifestRecord.FromDomain(manifest);
        var filter = Builders<VexExportManifestRecord>.Filter.Eq(x => x.Id, entity.Id);
        await _collection.ReplaceOneAsync(filter, entity, new ReplaceOptions { IsUpsert = true }, cancellationToken)
            .ConfigureAwait(false);
    }

    private static void EnsureIndexes(IMongoCollection<VexExportManifestRecord> collection)
    {
        var keys = Builders<VexExportManifestRecord>.IndexKeys
            .Ascending(x => x.QuerySignature)
            .Ascending(x => x.Format);
        var model = new CreateIndexModel<VexExportManifestRecord>(keys);
        _ = collection.Indexes.CreateOne(model);
    }
}
