using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using MongoDB.Driver;

namespace StellaOps.Feedser.Storage.Mongo.PsirtFlags;

public sealed class PsirtFlagStore : IPsirtFlagStore
{
    private readonly IMongoCollection<PsirtFlagDocument> _collection;
    private readonly ILogger<PsirtFlagStore> _logger;

    public PsirtFlagStore(IMongoDatabase database, ILogger<PsirtFlagStore> logger)
    {
        ArgumentNullException.ThrowIfNull(database);
        ArgumentNullException.ThrowIfNull(logger);

        _collection = database.GetCollection<PsirtFlagDocument>(MongoStorageDefaults.Collections.PsirtFlags);
        _logger = logger;
    }

    public async Task UpsertAsync(PsirtFlagRecord record, CancellationToken cancellationToken)
    {
        ArgumentNullException.ThrowIfNull(record);
        ArgumentException.ThrowIfNullOrEmpty(record.AdvisoryKey);

        var document = PsirtFlagDocumentExtensions.FromRecord(record);
        var filter = Builders<PsirtFlagDocument>.Filter.Eq(x => x.AdvisoryKey, record.AdvisoryKey);
        var options = new ReplaceOptions { IsUpsert = true };

        try
        {
            await _collection.ReplaceOneAsync(filter, document, options, cancellationToken).ConfigureAwait(false);
            _logger.LogDebug("Upserted PSIRT flag for {AdvisoryKey}", record.AdvisoryKey);
        }
        catch (MongoWriteException ex) when (ex.WriteError?.Category == ServerErrorCategory.DuplicateKey)
        {
            _logger.LogWarning(ex, "Duplicate PSIRT flag detected for {AdvisoryKey}", record.AdvisoryKey);
        }
    }

    public async Task<PsirtFlagRecord?> FindAsync(string advisoryKey, CancellationToken cancellationToken)
    {
        ArgumentException.ThrowIfNullOrEmpty(advisoryKey);

        var filter = Builders<PsirtFlagDocument>.Filter.Eq(x => x.AdvisoryKey, advisoryKey);
        var document = await _collection.Find(filter).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
        return document?.ToRecord();
    }
}
