using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Driver;

namespace StellaOps.Excititor.Storage.Mongo;

public sealed class MongoVexConnectorStateRepository : IVexConnectorStateRepository
{
    private readonly IMongoCollection<VexConnectorStateDocument> _collection;

    public MongoVexConnectorStateRepository(IMongoDatabase database)
    {
        ArgumentNullException.ThrowIfNull(database);
        VexMongoMappingRegistry.Register();
        _collection = database.GetCollection<VexConnectorStateDocument>(VexMongoCollectionNames.ConnectorState);
    }

    public async ValueTask<VexConnectorState?> GetAsync(string connectorId, CancellationToken cancellationToken)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(connectorId);

        var filter = Builders<VexConnectorStateDocument>.Filter.Eq(x => x.ConnectorId, connectorId.Trim());
        var document = await _collection.Find(filter).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
        return document?.ToRecord();
    }

    public async ValueTask SaveAsync(VexConnectorState state, CancellationToken cancellationToken)
    {
        ArgumentNullException.ThrowIfNull(state);

        var document = VexConnectorStateDocument.FromRecord(state.WithNormalizedDigests());
        var filter = Builders<VexConnectorStateDocument>.Filter.Eq(x => x.ConnectorId, document.ConnectorId);
        await _collection.ReplaceOneAsync(filter, document, new ReplaceOptions { IsUpsert = true }, cancellationToken).ConfigureAwait(false);
    }
}

internal static class VexConnectorStateExtensions
{
    private const int MaxDigestHistory = 200;

    public static VexConnectorState WithNormalizedDigests(this VexConnectorState state)
    {
        var digests = state.DocumentDigests;
        if (digests.Length <= MaxDigestHistory)
        {
            return state;
        }

        var trimmed = digests.Skip(digests.Length - MaxDigestHistory).ToImmutableArray();
        return state with { DocumentDigests = trimmed };
    }
}
