using Xunit;
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;        // DriverDataType
using ZB.MOM.WW.HistorianGateway.Contracts.Grpc;  // HistorianDataType
using ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Mapping;

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

public sealed class HistorianTypeMapperTests
{
    [Theory]
    [InlineData(DriverDataType.Boolean, HistorianDataType.Int2)]  // Int1 analog-tag creation is server-degenerate (issue #441) → store 0/1
    [InlineData(DriverDataType.Int16,   HistorianDataType.Int2)]
    [InlineData(DriverDataType.Int32,   HistorianDataType.Int4)]
    [InlineData(DriverDataType.Int64,   HistorianDataType.Int8)]
    [InlineData(DriverDataType.UInt16,  HistorianDataType.Uint4)]  // fallback: UInt2 write deferred upstream
    [InlineData(DriverDataType.UInt32,  HistorianDataType.Uint4)]
    [InlineData(DriverDataType.UInt64,  HistorianDataType.Uint8)]
    [InlineData(DriverDataType.Float32, HistorianDataType.Float)]
    [InlineData(DriverDataType.Float64, HistorianDataType.Double)]
    public void Maps_writable_numeric_types(DriverDataType d, HistorianDataType expected)
        => Assert.Equal(expected, HistorianTypeMapper.ToHistorianDataType(d));

    [Theory]
    [InlineData(DriverDataType.String)]
    [InlineData(DriverDataType.DateTime)]
    [InlineData(DriverDataType.Reference)]
    public void Deferred_types_throw_NotSupported_with_clear_message(DriverDataType d)
    {
        var ex = Assert.Throws<NotSupportedException>(() => HistorianTypeMapper.ToHistorianDataType(d));
        Assert.Contains("not historized in v1", ex.Message);  // human-actionable, no tag value leaked
    }

    [Fact] // matrix guard: a new DriverDataType member must be classified (mapped or explicitly deferred)
    public void Every_DriverDataType_member_is_classified()
    {
        foreach (var d in Enum.GetValues<DriverDataType>())
        {
            try { _ = HistorianTypeMapper.ToHistorianDataType(d); }
            catch (NotSupportedException) { /* explicitly deferred — acceptable */ }
            // any OTHER exception (e.g. ArgumentOutOfRangeException from an unhandled new member) fails the test
        }
    }

    [Theory]
    [InlineData(DriverDataType.Boolean, true)]
    [InlineData(DriverDataType.Float64, true)]
    [InlineData(DriverDataType.String,  false)]
    [InlineData(DriverDataType.DateTime, false)]
    [InlineData(DriverDataType.Reference, false)]
    public void IsHistorizable_matches_writable_set(DriverDataType d, bool expected)
        => Assert.Equal(expected, HistorianTypeMapper.IsHistorizable(d));
}
