using FluentAssertions;
using Xunit;
using ZB.MOM.WW.LmxProxy.Client.Domain;

namespace ZB.MOM.WW.LmxProxy.Client.Tests;

public class TypedValueConversionTests
{
    [Fact]
    public void ConvertVtqMessage_ExtractsBoolValue()
    {
        var msg = CreateVtqMessage(new TypedValue { BoolValue = true });

        var vtq = LmxProxyClient.ConvertVtqMessage(msg);

        vtq.Value.Should().Be(true);
    }

    [Fact]
    public void ConvertVtqMessage_ExtractsInt32Value()
    {
        var msg = CreateVtqMessage(new TypedValue { Int32Value = 42 });

        var vtq = LmxProxyClient.ConvertVtqMessage(msg);

        vtq.Value.Should().Be(42);
    }

    [Fact]
    public void ConvertVtqMessage_ExtractsInt64Value()
    {
        var msg = CreateVtqMessage(new TypedValue { Int64Value = long.MaxValue });

        var vtq = LmxProxyClient.ConvertVtqMessage(msg);

        vtq.Value.Should().Be(long.MaxValue);
    }

    [Fact]
    public void ConvertVtqMessage_ExtractsFloatValue()
    {
        var msg = CreateVtqMessage(new TypedValue { FloatValue = 3.14f });

        var vtq = LmxProxyClient.ConvertVtqMessage(msg);

        vtq.Value.Should().Be(3.14f);
    }

    [Fact]
    public void ConvertVtqMessage_ExtractsDoubleValue()
    {
        var msg = CreateVtqMessage(new TypedValue { DoubleValue = 99.99 });

        var vtq = LmxProxyClient.ConvertVtqMessage(msg);

        vtq.Value.Should().Be(99.99);
    }

    [Fact]
    public void ConvertVtqMessage_ExtractsStringValue()
    {
        var msg = CreateVtqMessage(new TypedValue { StringValue = "hello" });

        var vtq = LmxProxyClient.ConvertVtqMessage(msg);

        vtq.Value.Should().Be("hello");
    }

    [Fact]
    public void ConvertVtqMessage_ExtractsDateTimeValue()
    {
        var dt = new DateTime(2026, 3, 22, 12, 0, 0, DateTimeKind.Utc);
        var msg = CreateVtqMessage(new TypedValue { DatetimeValue = dt.Ticks });

        var vtq = LmxProxyClient.ConvertVtqMessage(msg);

        vtq.Value.Should().BeOfType<DateTime>();
        ((DateTime)vtq.Value!).Should().Be(dt);
    }

    [Fact]
    public void ConvertVtqMessage_HandlesNullTypedValue()
    {
        var msg = new VtqMessage
        {
            Tag = "NullTag",
            Value = null,
            TimestampUtcTicks = DateTime.UtcNow.Ticks,
            Quality = new QualityCode { StatusCode = 0x00000000 }
        };

        var vtq = LmxProxyClient.ConvertVtqMessage(msg);

        vtq.Value.Should().BeNull();
    }

    [Fact]
    public void ConvertVtqMessage_HandlesNullMessage()
    {
        var vtq = LmxProxyClient.ConvertVtqMessage(null);

        vtq.Value.Should().BeNull();
        vtq.Quality.Should().Be(Quality.Bad);
    }

    [Fact]
    public void ConvertVtqMessage_GoodQualityCode()
    {
        var msg = CreateVtqMessage(new TypedValue { DoubleValue = 1.0 }, statusCode: 0x00000000);

        var vtq = LmxProxyClient.ConvertVtqMessage(msg);

        vtq.Quality.Should().Be(Quality.Good);
    }

    [Fact]
    public void ConvertVtqMessage_BadQualityCode()
    {
        var msg = CreateVtqMessage(new TypedValue { DoubleValue = 1.0 }, statusCode: 0x80000000);

        var vtq = LmxProxyClient.ConvertVtqMessage(msg);

        vtq.Quality.Should().Be(Quality.Bad);
    }

    [Fact]
    public void ConvertVtqMessage_UncertainQualityCode()
    {
        var msg = CreateVtqMessage(new TypedValue { DoubleValue = 1.0 }, statusCode: 0x40000000);

        var vtq = LmxProxyClient.ConvertVtqMessage(msg);

        vtq.Quality.Should().Be(Quality.Uncertain);
    }

    [Fact]
    public void ConvertVtqMessage_MapsQualityCodeCorrectly()
    {
        // Test that a specific non-zero Good code still maps to Good
        var msg = CreateVtqMessage(new TypedValue { Int32Value = 5 }, statusCode: 0x00D80000);

        var vtq = LmxProxyClient.ConvertVtqMessage(msg);

        vtq.Quality.Should().Be(Quality.Good);
    }

    private static VtqMessage CreateVtqMessage(TypedValue value, uint statusCode = 0x00000000)
    {
        return new VtqMessage
        {
            Tag = "TestTag",
            Value = value,
            TimestampUtcTicks = new DateTime(2026, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks,
            Quality = new QualityCode { StatusCode = statusCode }
        };
    }
}
