using ZB.MOM.WW.MxGateway.Contracts.Proto.Galaxy;
using ZB.MOM.WW.MxGateway.Server.Galaxy;
using ZB.MOM.WW.MxGateway.Server.Grpc;

namespace ZB.MOM.WW.MxGateway.Tests.Galaxy;

public sealed class GalaxyProtoMapperTests
{
    /// <summary>Verifies that mapping a galaxy attribute row preserves all scalar fields.</summary>
    [Fact]
    public void MapAttribute_PreservesAllScalarFields()
    {
        GalaxyAttributeRow row = new()
        {
            GobjectId = 42,
            TagName = "Pump_001",
            AttributeName = "Speed",
            FullTagReference = "Pump_001.Speed",
            MxDataType = 3,
            DataTypeName = "Float",
            IsArray = false,
            ArrayDimension = null,
            MxAttributeCategory = 5,
            SecurityClassification = 2,
            IsHistorized = true,
            IsAlarm = false,
        };

        GalaxyAttribute proto = GalaxyProtoMapper.MapAttribute(row);

        Assert.Equal("Speed", proto.AttributeName);
        Assert.Equal("Pump_001.Speed", proto.FullTagReference);
        Assert.Equal(3, proto.MxDataType);
        Assert.Equal("Float", proto.DataTypeName);
        Assert.False(proto.IsArray);
        Assert.Equal(0, proto.ArrayDimension);
        Assert.False(proto.ArrayDimensionPresent);
        Assert.Equal(5, proto.MxAttributeCategory);
        Assert.Equal(2, proto.SecurityClassification);
        Assert.True(proto.IsHistorized);
        Assert.False(proto.IsAlarm);
    }

    /// <summary>Verifies that the array dimension present flag distinguishes null from zero.</summary>
    [Fact]
    public void MapAttribute_ArrayDimensionPresentFlag_DistinguishesNullFromZero()
    {
        GalaxyAttributeRow withDim = new() { ArrayDimension = 0, IsArray = true };
        GalaxyAttributeRow withoutDim = new() { ArrayDimension = null, IsArray = false };

        Assert.True(GalaxyProtoMapper.MapAttribute(withDim).ArrayDimensionPresent);
        Assert.Equal(0, GalaxyProtoMapper.MapAttribute(withDim).ArrayDimension);

        Assert.False(GalaxyProtoMapper.MapAttribute(withoutDim).ArrayDimensionPresent);
        Assert.Equal(0, GalaxyProtoMapper.MapAttribute(withoutDim).ArrayDimension);
    }

    /// <summary>Verifies that null data type name becomes an empty string.</summary>
    [Fact]
    public void MapAttribute_NullDataTypeName_BecomesEmptyString()
    {
        GalaxyAttributeRow row = new() { DataTypeName = null };

        GalaxyAttribute proto = GalaxyProtoMapper.MapAttribute(row);

        Assert.Equal(string.Empty, proto.DataTypeName);
    }

    /// <summary>Verifies that MapHierarchy groups attributes by GobjectId.</summary>
    [Fact]
    public void MapHierarchy_GroupsAttributesByGobjectId()
    {
        List<GalaxyHierarchyRow> hierarchy =
        [
            new() { GobjectId = 1, TagName = "A", BrowseName = "A", TemplateChain = ["RootTpl"] },
            new() { GobjectId = 2, TagName = "B", BrowseName = "B", ParentGobjectId = 1 },
            new() { GobjectId = 3, TagName = "C", BrowseName = "C", ParentGobjectId = 1 },
        ];
        List<GalaxyAttributeRow> attributes =
        [
            new() { GobjectId = 1, AttributeName = "X", FullTagReference = "A.X" },
            new() { GobjectId = 2, AttributeName = "Y1", FullTagReference = "B.Y1" },
            new() { GobjectId = 2, AttributeName = "Y2", FullTagReference = "B.Y2" },
        ];

        List<GalaxyObject> result = GalaxyProtoMapper.MapHierarchy(hierarchy, attributes).ToList();

        Assert.Equal(3, result.Count);
        Assert.Single(result[0].Attributes);
        Assert.Equal("X", result[0].Attributes[0].AttributeName);
        Assert.Equal(2, result[1].Attributes.Count);
        Assert.Empty(result[2].Attributes);
    }

    /// <summary>Verifies that MapObject copies the template chain.</summary>
    [Fact]
    public void MapObject_CopiesTemplateChain()
    {
        GalaxyHierarchyRow row = new()
        {
            GobjectId = 5,
            TagName = "Engine_001",
            ContainedName = "Engine",
            BrowseName = "Engine",
            TemplateChain = ["EngineTpl", "AppEngineBase"],
        };

        GalaxyObject proto = GalaxyProtoMapper.MapObject(
            row,
            new Dictionary<int, List<GalaxyAttributeRow>>());

        Assert.Equal(new[] { "EngineTpl", "AppEngineBase" }, proto.TemplateChain);
    }
}
