using ZB.MOM.WW.Configuration;

namespace ZB.MOM.WW.ScadaBridge.Host;

/// <summary>
/// Validates <see cref="NodeOptions"/> at host startup (arch-review 08 round 2
/// NF4). The headline invariant: <see cref="NodeOptions.NodeName"/> must be
/// non-empty — an empty value normalises to a NULL <c>SourceNode</c> audit
/// column, silently degrading the audit trail (the wonder-app-vd03 failure
/// mode), so the host must fail fast at boot instead. Ports are bounded to the
/// TCP range; <c>0</c> stays valid because it requests a dynamically-assigned
/// port (CompositionRootTests rely on this).
/// </summary>
public sealed class NodeOptionsValidator : OptionsValidatorBase<NodeOptions>
{
    /// <inheritdoc />
    protected override void Validate(ValidationBuilder builder, NodeOptions options)
    {
        builder.RequireThat(!string.IsNullOrWhiteSpace(options.NodeName),
            $"ScadaBridge:Node:{nameof(NodeOptions.NodeName)} must be a non-empty label " +
            "— an empty node name stamps the SourceNode audit column NULL.");

        RequirePort(builder, options.RemotingPort, nameof(NodeOptions.RemotingPort));
        RequirePort(builder, options.GrpcPort, nameof(NodeOptions.GrpcPort));
        RequirePort(builder, options.MetricsPort, nameof(NodeOptions.MetricsPort));
        RequirePort(builder, options.CentralGrpcPort, nameof(NodeOptions.CentralGrpcPort));
    }

    // 0 stays valid (dynamic-port request); reject only out-of-TCP-range values.
    private static void RequirePort(ValidationBuilder builder, int port, string field)
    {
        builder.RequireThat(port is >= 0 and <= 65_535,
            $"ScadaBridge:Node:{field} ({port}) must be in [0, 65535].");
    }
}
