using MongoDB.Driver;

namespace StellaOps.Feedser.Storage.Mongo;

public sealed class MongoStorageOptions
{
    public string ConnectionString { get; set; } = string.Empty;

    public string? DatabaseName { get; set; }

    public TimeSpan CommandTimeout { get; set; } = TimeSpan.FromSeconds(30);

    /// <summary>
    /// Retention period for raw documents (document + DTO + GridFS payloads).
    /// Set to <see cref="TimeSpan.Zero"/> to disable automatic expiry.
    /// </summary>
    public TimeSpan RawDocumentRetention { get; set; } = TimeSpan.FromDays(45);

    /// <summary>
    /// Additional grace period applied on top of <see cref="RawDocumentRetention"/> before TTL purges old rows.
    /// Allows the retention background service to delete GridFS blobs first.
    /// </summary>
    public TimeSpan RawDocumentRetentionTtlGrace { get; set; } = TimeSpan.FromDays(1);

    /// <summary>
    /// Interval between retention sweeps. Only used when <see cref="RawDocumentRetention"/> is greater than zero.
    /// </summary>
    public TimeSpan RawDocumentRetentionSweepInterval { get; set; } = TimeSpan.FromHours(6);

    /// <summary>
    /// Enables dual-write of normalized SemVer analytics for affected packages.
    /// </summary>
    public bool EnableSemVerStyle { get; set; } = true;

    /// <summary>
    /// Batch size used by backfill migrations when repopulating normalized version documents.
    /// </summary>
    public int BackfillBatchSize { get; set; } = 250;

    public string GetDatabaseName()
    {
        if (!string.IsNullOrWhiteSpace(DatabaseName))
        {
            return DatabaseName.Trim();
        }

        if (!string.IsNullOrWhiteSpace(ConnectionString))
        {
            var url = MongoUrl.Create(ConnectionString);
            if (!string.IsNullOrWhiteSpace(url.DatabaseName))
            {
                return url.DatabaseName;
            }
        }

        return MongoStorageDefaults.DefaultDatabaseName;
    }

    public void EnsureValid()
    {
        if (string.IsNullOrWhiteSpace(ConnectionString))
        {
            throw new InvalidOperationException("Mongo connection string is not configured.");
        }

        if (CommandTimeout <= TimeSpan.Zero)
        {
            throw new InvalidOperationException("Command timeout must be greater than zero.");
        }

        if (RawDocumentRetention < TimeSpan.Zero)
        {
            throw new InvalidOperationException("Raw document retention cannot be negative.");
        }

        if (RawDocumentRetentionTtlGrace < TimeSpan.Zero)
        {
            throw new InvalidOperationException("Raw document retention TTL grace cannot be negative.");
        }

        if (RawDocumentRetention > TimeSpan.Zero && RawDocumentRetentionSweepInterval <= TimeSpan.Zero)
        {
            throw new InvalidOperationException("Raw document retention sweep interval must be positive when retention is enabled.");
        }

        if (BackfillBatchSize <= 0)
        {
            throw new InvalidOperationException("Backfill batch size must be greater than zero.");
        }

        _ = GetDatabaseName();
    }
}
