using System;
using ZB.MOM.WW.MxGateway.Worker.MxAccess;

namespace ZB.MOM.WW.MxGateway.Worker.Tests.MxAccess;

/// <summary>
///     Unit tests for <see cref="SyntheticAlarmGuid"/>: the subtag-fallback
///     path derives a deterministic GUID from the alarm reference, so identical
///     references must collide and distinct references must not.
/// </summary>
public sealed class SyntheticAlarmGuidTests
{
    /// <summary>Verifies the same reference yields the same GUID.</summary>
    [Fact]
    public void SameReference_SameGuid() =>
        Assert.Equal(SyntheticAlarmGuid.ForReference("A.B.C"), SyntheticAlarmGuid.ForReference("A.B.C"));

    /// <summary>Verifies distinct references yield distinct GUIDs.</summary>
    [Fact]
    public void DifferentReference_DifferentGuid() =>
        Assert.NotEqual(SyntheticAlarmGuid.ForReference("A.B.C"), SyntheticAlarmGuid.ForReference("A.B.D"));

    /// <summary>Verifies a reference produces a non-empty GUID.</summary>
    [Fact]
    public void Reference_ProducesNonEmptyGuid() =>
        Assert.NotEqual(Guid.Empty, SyntheticAlarmGuid.ForReference("A.B.C"));

    /// <summary>
    ///     Verifies the empty string still derives a non-empty GUID. The length
    ///     fold in the derivation prevents a degenerate all-zero (Guid.Empty)
    ///     result, which would collide with the unset-record default downstream.
    /// </summary>
    [Fact]
    public void EmptyReference_ProducesNonEmptyGuid() =>
        Assert.NotEqual(Guid.Empty, SyntheticAlarmGuid.ForReference(string.Empty));

    /// <summary>
    ///     Regression test: <see cref="SyntheticAlarmGuid.ForReference"/>
    ///     must derive its GUID without routing through
    ///     <see cref="System.Security.Cryptography"/>, because on net48
    ///     <c>MD5.Create()</c> throws under the Windows FIPS-compliance policy.
    ///     This test enables the per-AppContext FIPS-enforcement switch (which the
    ///     managed crypto factories honour) and asserts the derivation still
    ///     succeeds deterministically — a regression that reintroduced a FIPS-gated
    ///     provider would throw here instead of returning a stable GUID.
    /// </summary>
    [Fact]
    public void ForReference_UnderFipsEnforcement_DoesNotThrowAndStaysDeterministic()
    {
        const string switchName = "Switch.System.Security.Cryptography.UseLegacyFipsThrow";
        bool original = AppContext.TryGetSwitch(switchName, out bool value) && value;
        AppContext.SetSwitch(switchName, true);
        try
        {
            Guid first = SyntheticAlarmGuid.ForReference("Galaxy!Area.Tank01.Level.HiHi");
            Guid second = SyntheticAlarmGuid.ForReference("Galaxy!Area.Tank01.Level.HiHi");

            Assert.NotEqual(Guid.Empty, first);
            Assert.Equal(first, second);
        }
        finally
        {
            AppContext.SetSwitch(switchName, original);
        }
    }
}
