using ZB.MOM.WW.Configuration;
namespace ZB.MOM.WW.ScadaBridge.SiteEventLogging;
///
/// Validates at startup. Retention/purge values
/// drive the daily purge PeriodicTimer (a zero/negative period trips
/// ), the paging bounds gate query result
/// sizes, and the write-queue capacity sizes a bounded channel; a
/// MaxQueryPageSize below QueryPageSize would silently clamp the
/// default page below itself. Registered with ValidateOnStart() so a bad
/// ScadaBridge:SiteEventLog section fails fast at boot with a clear,
/// key-naming message.
///
public sealed class SiteEventLogOptionsValidator : OptionsValidatorBase
{
///
protected override void Validate(ValidationBuilder builder, SiteEventLogOptions options)
{
builder.RequireThat(options.RetentionDays > 0,
$"ScadaBridge:SiteEventLog:RetentionDays must be greater than 0 " +
$"(was {options.RetentionDays}).");
builder.RequireThat(options.MaxStorageMb > 0,
$"ScadaBridge:SiteEventLog:MaxStorageMb must be greater than 0 " +
$"(was {options.MaxStorageMb}).");
builder.RequireThat(!string.IsNullOrWhiteSpace(options.DatabasePath),
"ScadaBridge:SiteEventLog:DatabasePath must be a non-empty path; " +
"it is the SQLite file backing the site event log.");
builder.RequireThat(options.QueryPageSize > 0,
$"ScadaBridge:SiteEventLog:QueryPageSize must be greater than 0 " +
$"(was {options.QueryPageSize}).");
builder.RequireThat(options.WriteQueueCapacity > 0,
$"ScadaBridge:SiteEventLog:WriteQueueCapacity must be greater than 0 " +
$"(was {options.WriteQueueCapacity}); it bounds the background write channel.");
builder.RequireThat(options.PurgeInterval > TimeSpan.Zero,
$"ScadaBridge:SiteEventLog:PurgeInterval must be a positive duration " +
$"(was {options.PurgeInterval}); it is the purge PeriodicTimer period.");
// A NEGATIVE ceiling is a config error, not a synonym for "unlimited": 0 already
// carries that meaning explicitly, and silently treating -1 the same way would hide
// a typo that removes the only bound on a purge burst's oplog cost.
builder.RequireThat(options.MaxPurgedRowsPerTick >= 0,
$"ScadaBridge:SiteEventLog:MaxPurgedRowsPerTick must be 0 (unlimited) or greater " +
$"(was {options.MaxPurgedRowsPerTick}); it bounds how many rows one purge tick deletes.");
builder.RequireThat(options.PurgeCatchUpInterval > TimeSpan.Zero,
$"ScadaBridge:SiteEventLog:PurgeCatchUpInterval must be a positive duration " +
$"(was {options.PurgeCatchUpInterval}); it is the delay before the next tick when a " +
"purge stopped at MaxPurgedRowsPerTick.");
// A catch-up longer than the ordinary interval would make hitting the ceiling SLOW the
// purge down, which inverts the whole point of the accelerated retry. Only compared when
// both are positive (each owned above), so a bad value fires exactly one message.
builder.RequireThat(
!(options.PurgeInterval > TimeSpan.Zero
&& options.PurgeCatchUpInterval > TimeSpan.Zero
&& options.PurgeCatchUpInterval > options.PurgeInterval),
$"ScadaBridge:SiteEventLog:PurgeCatchUpInterval ({options.PurgeCatchUpInterval}) must be " +
$"less than or equal to PurgeInterval ({options.PurgeInterval}): it is an ACCELERATED " +
"retry after a ceiling-limited tick, so a longer value would delay convergence instead.");
// The hard page-size ceiling clamps a caller-supplied PageSize; a ceiling
// below the default QueryPageSize would silently clamp the default below
// itself. Only meaningful when both are positive (owned above), so stay
// silent when either is non-positive rather than double-firing.
builder.RequireThat(
!(options.QueryPageSize > 0
&& options.MaxQueryPageSize > 0
&& options.MaxQueryPageSize < options.QueryPageSize),
$"ScadaBridge:SiteEventLog:MaxQueryPageSize ({options.MaxQueryPageSize}) " +
$"must be >= QueryPageSize ({options.QueryPageSize}): the ceiling clamps a caller's " +
"requested page size, so it cannot be smaller than the default page size.");
}
}