using Google.Protobuf.WellKnownTypes;
using Xunit;
using ZB.MOM.WW.HistorianGateway.Contracts.Grpc;
using ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Mapping;

namespace ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Tests.Mapping;

public sealed class SampleMapperTests
{
    [Fact]
    public void Numeric_sample_maps_value_quality_and_timestamps()
    {
        var s = new HistorianSample { Tag = "T", NumericValue = 12.5,
            Quality = 192, OpcQuality = 192, Timestamp = Ts(2026, 1, 1, 0, 0, 0) };
        var snap = SampleMapper.ToSnapshot(s);
        Assert.Equal(12.5, Assert.IsType<double>(snap.Value));
        Assert.Equal(0x00000000u, snap.StatusCode);
        Assert.Equal(DateTimeKind.Utc, snap.SourceTimestampUtc!.Value.Kind);
    }

    [Fact]
    public void String_sample_carries_string_value()
    {
        var s = new HistorianSample { Tag = "T", StringValue = "abc", OpcQuality = 192, Timestamp = Ts(2026, 1, 1, 0, 0, 0) };
        Assert.Equal("abc", SampleMapper.ToSnapshot(s).Value);
    }

    [Fact]
    public void Bad_quality_sample_maps_to_bad_status()
    {
        var s = new HistorianSample { Tag = "T", NumericValue = 1.0, OpcQuality = 0, Timestamp = Ts(2026, 1, 1, 0, 0, 0) };
        Assert.Equal(0x80000000u, SampleMapper.ToSnapshot(s).StatusCode);
    }

    [Fact]
    public void Aggregate_null_value_is_BadNoData()
    {
        var a = new HistorianAggregateSample { Tag = "T", /* Value unset, no Good quality */ EndTime = Ts(2026, 1, 1, 0, 0, 0) };
        var snap = SampleMapper.ToAggregateSnapshot(a);
        Assert.Equal(0x809B0000u, snap.StatusCode); // BadNoData
        Assert.Null(snap.Value);
    }

    [Fact]
    public void Aggregate_good_bucket_carries_value()
    {
        var a = new HistorianAggregateSample { Tag = "T", Value = 42.0, OpcQuality = 192, EndTime = Ts(2026, 1, 1, 0, 0, 0) };
        var snap = SampleMapper.ToAggregateSnapshot(a);
        Assert.Equal(0x00000000u, snap.StatusCode); // Good
        Assert.Equal(42.0, Assert.IsType<double>(snap.Value));
    }

    // Ts(...) builds a Google.Protobuf.WellKnownTypes.Timestamp from UTC parts.
    private static Timestamp Ts(int y, int mo, int d, int h, int mi, int s)
        => Timestamp.FromDateTime(new DateTime(y, mo, d, h, mi, s, DateTimeKind.Utc));
}
