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

namespace StellaOps.Vexer.Storage.Mongo;

public sealed class MongoVexCacheIndex : IVexCacheIndex
{
    private readonly IMongoCollection<VexCacheEntryRecord> _collection;

    public MongoVexCacheIndex(IMongoDatabase database)
    {
        ArgumentNullException.ThrowIfNull(database);
        VexMongoMappingRegistry.Register();
        _collection = database.GetCollection<VexCacheEntryRecord>(VexMongoCollectionNames.Cache);
    }

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

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

    public async ValueTask RemoveAsync(VexQuerySignature signature, VexExportFormat format, CancellationToken cancellationToken)
    {
        ArgumentNullException.ThrowIfNull(signature);
        var filter = Builders<VexCacheEntryRecord>.Filter.Eq(x => x.Id, VexCacheEntryRecord.CreateId(signature, format));
        await _collection.DeleteOneAsync(filter, cancellationToken).ConfigureAwait(false);
    }
}
