using MongoDB.Driver;
using StellaOps.Authority.Storage.Mongo.Documents;

namespace StellaOps.Authority.Storage.Mongo.Initialization;

internal sealed class AuthorityTokenCollectionInitializer : IAuthorityCollectionInitializer
{
    public async ValueTask EnsureIndexesAsync(IMongoDatabase database, CancellationToken cancellationToken)
    {
        var collection = database.GetCollection<AuthorityTokenDocument>(AuthorityMongoDefaults.Collections.Tokens);

        var indexModels = new List<CreateIndexModel<AuthorityTokenDocument>>
        {
            new(
                Builders<AuthorityTokenDocument>.IndexKeys.Ascending(t => t.TokenId),
                new CreateIndexOptions<AuthorityTokenDocument> { Name = "token_id_unique", Unique = true }),
            new(
                Builders<AuthorityTokenDocument>.IndexKeys.Ascending(t => t.ReferenceId),
                new CreateIndexOptions<AuthorityTokenDocument> { Name = "token_reference_unique", Unique = true, Sparse = true }),
            new(
                Builders<AuthorityTokenDocument>.IndexKeys.Ascending(t => t.SubjectId),
                new CreateIndexOptions<AuthorityTokenDocument> { Name = "token_subject" }),
            new(
                Builders<AuthorityTokenDocument>.IndexKeys.Ascending(t => t.ClientId),
                new CreateIndexOptions<AuthorityTokenDocument> { Name = "token_client" }),
            new(
                Builders<AuthorityTokenDocument>.IndexKeys
                    .Ascending(t => t.Status)
                    .Ascending(t => t.RevokedAt),
                new CreateIndexOptions<AuthorityTokenDocument> { Name = "token_status_revokedAt" })
        };

        var expirationFilter = Builders<AuthorityTokenDocument>.Filter.Exists(t => t.ExpiresAt, true);
        indexModels.Add(new CreateIndexModel<AuthorityTokenDocument>(
            Builders<AuthorityTokenDocument>.IndexKeys.Ascending(t => t.ExpiresAt),
            new CreateIndexOptions<AuthorityTokenDocument>
            {
                Name = "token_expiry_ttl",
                ExpireAfter = TimeSpan.Zero,
                PartialFilterExpression = expirationFilter
            }));

        await collection.Indexes.CreateManyAsync(indexModels, cancellationToken).ConfigureAwait(false);
    }
}
