using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
using ZB.MOM.WW.OtOpcUa.Core.Resilience;

namespace ZB.MOM.WW.OtOpcUa.Core.Tests.Resilience;

/// <summary>
///     Load-bearing regression guard for 01/S-6 — an operator-authorable out-of-range
///     ResilienceConfig value must NEVER brick a healthy driver. Before the R2-02 hardening pass,
///     <c>"timeoutSeconds": 0</c> (→ <c>TimeSpan.Zero</c>, outside Polly's [10 ms, 24 h] window) and
///     <c>"breakerFailureThreshold": 1</c> (below Polly's MinimumThroughput floor of 2) each made
///     <see cref="DriverResiliencePipelineBuilder"/> throw <c>ValidationException</c> inside the
///     memoizing <c>GetOrAdd</c> factory on EVERY capability call for that (instance, host,
///     capability) — a permanent brick while the driver is healthy. The parser now clamps and the
///     builder belt-and-braces clamps, so a pipeline built from a parsed hostile config executes.
/// </summary>
[Trait("Category", "Unit")]
public sealed class ResilienceConfigBrickTests
{
    /// <summary>A parsed <c>timeoutSeconds:0</c> override must not brick a capability call.</summary>
    [Fact]
    public async Task ParsedConfig_WithZeroTimeout_DoesNotBrickCapabilityCalls()
    {
        var options = DriverResilienceOptionsParser.ParseOrDefaults(
            DriverTier.A, "{\"capabilityPolicies\":{\"Read\":{\"timeoutSeconds\":0}}}", out _);

        var pipeline = new DriverResiliencePipelineBuilder()
            .GetOrCreate("i1", "h1", DriverCapability.Read, options);

        var result = await pipeline.ExecuteAsync(_ => ValueTask.FromResult(42), CancellationToken.None);
        result.ShouldBe(42);
    }

    /// <summary>A parsed <c>breakerFailureThreshold:1</c> override must not brick a capability call.</summary>
    [Fact]
    public async Task ParsedConfig_WithBreakerThresholdOne_DoesNotBrickCapabilityCalls()
    {
        var options = DriverResilienceOptionsParser.ParseOrDefaults(
            DriverTier.A, "{\"capabilityPolicies\":{\"Read\":{\"breakerFailureThreshold\":1}}}", out _);

        var pipeline = new DriverResiliencePipelineBuilder()
            .GetOrCreate("i1", "h1", DriverCapability.Read, options);

        var result = await pipeline.ExecuteAsync(_ => ValueTask.FromResult(42), CancellationToken.None);
        result.ShouldBe(42);
    }
}
