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

namespace StellaOps.Vexer.Storage.Mongo;

public sealed class MongoVexProviderStore : IVexProviderStore
{
    private readonly IMongoCollection<VexProviderRecord> _collection;

    public MongoVexProviderStore(IMongoDatabase database)
    {
        ArgumentNullException.ThrowIfNull(database);
        VexMongoMappingRegistry.Register();
        _collection = database.GetCollection<VexProviderRecord>(VexMongoCollectionNames.Providers);
    }

    public async ValueTask<VexProvider?> FindAsync(string id, CancellationToken cancellationToken)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(id);
        var filter = Builders<VexProviderRecord>.Filter.Eq(x => x.Id, id.Trim());
        var record = await _collection.Find(filter).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
        return record?.ToDomain();
    }

    public async ValueTask<IReadOnlyCollection<VexProvider>> ListAsync(CancellationToken cancellationToken)
    {
        var records = await _collection.Find(FilterDefinition<VexProviderRecord>.Empty)
            .Sort(Builders<VexProviderRecord>.Sort.Ascending(x => x.Id))
            .ToListAsync(cancellationToken)
            .ConfigureAwait(false);

        return records.ConvertAll(static record => record.ToDomain());
    }

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