namespace ZB.MOM.WW.ScadaBridge.AuditLog.Site;

/// <summary>
/// Configuration for the site-side SQLite retention purge.
/// The site audit store is ephemeral (~7-day retention); <see cref="SiteAuditRetentionService"/>
/// runs <see cref="ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services.ISiteAuditQueue.PurgeExpiredAsync"/>
/// on a timer using these knobs. Mirrors the resolve/clamp shape of
/// <c>SiteCallAuditOptions</c> so a misconfigured value can never make the timer spin
/// or the retention window collapse.
/// </summary>
public class SiteAuditRetentionOptions
{
    /// <summary>
    /// Configuration section path bound in the site host. Follows the component's
    /// existing <c>AuditLog:*</c> convention (sibling of <c>AuditLog:SiteWriter</c>,
    /// <c>AuditLog:Purge</c>, …), not an application-root-absolute path.
    /// </summary>
    public const string SectionName = "AuditLog:SiteRetention";

    /// <summary>
    /// Retention window in days. On each purge tick, Forwarded/Reconciled rows whose
    /// <c>OccurredAtUtc</c> is older than <c>UtcNow - ResolvedRetentionDays</c> are
    /// deleted (Pending rows are never purged on age alone). Default 7. Resolved value
    /// is clamped to <see cref="MinRetentionDays"/>..<see cref="MaxRetentionDays"/>.
    /// </summary>
    public int RetentionDays { get; set; } = 7;

    private const int MinRetentionDays = 1;
    private const int MaxRetentionDays = 90;

    /// <summary>
    /// Effective retention window: <see cref="RetentionDays"/> clamped to
    /// [<see cref="MinRetentionDays"/>, <see cref="MaxRetentionDays"/>] so a
    /// misconfigured 0 (which would purge everything) or an unbounded value can
    /// never take effect.
    /// </summary>
    public int ResolvedRetentionDays =>
        RetentionDays < MinRetentionDays ? MinRetentionDays
        : RetentionDays > MaxRetentionDays ? MaxRetentionDays
        : RetentionDays;

    /// <summary>
    /// Period of the purge tick. Default 24 hours. Resolved value is clamped to at
    /// least <see cref="MinPurgeInterval"/> so a zero/negative config value cannot
    /// make the timer fire in a tight loop.
    /// </summary>
    public TimeSpan PurgeInterval { get; set; } = TimeSpan.FromHours(24);

    /// <summary>
    /// Test-only override for the purge cadence — bypasses the
    /// <see cref="MinPurgeInterval"/> clamp so unit tests can drop the period to
    /// milliseconds. Production config never sets this; leave null. Mirrors
    /// <c>SiteCallAuditOptions.PurgeIntervalOverride</c>.
    /// </summary>
    public TimeSpan? PurgeIntervalOverride { get; set; }

    private static readonly TimeSpan MinPurgeInterval = TimeSpan.FromMinutes(1);

    /// <summary>
    /// Effective purge period: the test override when set (bypassing the clamp),
    /// otherwise <see cref="PurgeInterval"/> clamped to at least
    /// <see cref="MinPurgeInterval"/> (the Timer/Akka zero-interval spin footgun).
    /// </summary>
    public TimeSpan ResolvedPurgeInterval =>
        PurgeIntervalOverride is { } o
            ? o
            : PurgeInterval < MinPurgeInterval
                ? MinPurgeInterval
                : PurgeInterval;

    /// <summary>
    /// Delay before the first purge tick. Default 5 minutes — short so a node that
    /// restarts daily (or more often) still runs the purge shortly after start
    /// rather than waiting a full <see cref="PurgeInterval"/> it may never reach.
    /// </summary>
    public TimeSpan InitialDelay { get; set; } = TimeSpan.FromMinutes(5);
}
