using Google.Protobuf.WellKnownTypes;
using ZB.MOM.WW.ScadaBridge.Communication.Grpc;

namespace ZB.MOM.WW.ScadaBridge.Communication.Tests.Grpc;

/// <summary>
/// Guardrail tests that verify all oneof variants in SiteStreamEvent have
/// corresponding conversion handlers. Adding a new proto field without
/// implementing the conversion will cause these tests to fail.
/// </summary>
public class ProtoContractTests
{
    /// <summary>
    /// The set of EventOneofCase values we handle in ConvertToDomainEvent.
    /// Update this array when adding a new oneof variant.
    /// </summary>
    private static readonly SiteStreamEvent.EventOneofCase[] HandledCases =
    [
        SiteStreamEvent.EventOneofCase.AttributeChanged,
        SiteStreamEvent.EventOneofCase.AlarmChanged
    ];

    [Fact]
    public void AllOneofVariants_HaveConversionHandlers()
    {
        var allCases = System.Enum.GetValues<SiteStreamEvent.EventOneofCase>()
            .Where(c => c != SiteStreamEvent.EventOneofCase.None)
            .ToArray();

        Assert.Equal(allCases.Length, HandledCases.Length);
        foreach (var c in allCases)
            Assert.Contains(c, HandledCases);
    }

    [Theory]
    [InlineData(SiteStreamEvent.EventOneofCase.AttributeChanged)]
    [InlineData(SiteStreamEvent.EventOneofCase.AlarmChanged)]
    public void ConvertToDomainEvent_HandlesAllOneofVariants(SiteStreamEvent.EventOneofCase eventCase)
    {
        var evt = CreateTestEvent(eventCase);
        var result = SiteStreamGrpcClient.ConvertToDomainEvent(evt);
        Assert.NotNull(result);
    }

    private static SiteStreamEvent CreateTestEvent(SiteStreamEvent.EventOneofCase eventCase)
    {
        var ts = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow);

        return eventCase switch
        {
            SiteStreamEvent.EventOneofCase.AttributeChanged => new SiteStreamEvent
            {
                CorrelationId = "test",
                AttributeChanged = new AttributeValueUpdate
                {
                    InstanceUniqueName = "Site1.Inst1",
                    AttributePath = "Path",
                    AttributeName = "Attr",
                    Value = "42",
                    Quality = Quality.Good,
                    Timestamp = ts
                }
            },
            SiteStreamEvent.EventOneofCase.AlarmChanged => new SiteStreamEvent
            {
                CorrelationId = "test",
                AlarmChanged = new AlarmStateUpdate
                {
                    InstanceUniqueName = "Site1.Inst1",
                    AlarmName = "HighTemp",
                    State = AlarmStateEnum.AlarmStateActive,
                    Priority = 1,
                    Timestamp = ts
                }
            },
            _ => throw new ArgumentOutOfRangeException(nameof(eventCase), eventCase, "Unhandled event case")
        };
    }
}
