using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.AdminUI.Uns;

namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Uns;

/// <summary>
/// Verifies <see cref="UnsTreeService.LoadEquipmentChildrenAsync"/> returns Tag leaf nodes
/// followed by VirtualTag leaf nodes, in Name order, with the correct keys and display names.
/// </summary>
[Trait("Category", "Unit")]
public sealed class UnsTreeServiceLazyTests
{
    private static UnsTreeService SeededService()
    {
        var dbName = $"uns-lazy-{Guid.NewGuid():N}";
        UnsTreeTestDb.SeedNamed(dbName);
        return new UnsTreeService(UnsTreeTestDb.Factory(dbName));
    }

    /// <summary>
    /// Tags come first, ordered by Name, then VirtualTags; keys follow the tag:/vtag: scheme
    /// and the Tag display name embeds the DataType.
    /// </summary>
    [Fact]
    public async Task LoadEquipmentChildren_returns_tags_then_vtags()
    {
        var service = SeededService();

        var children = await service.LoadEquipmentChildrenAsync(UnsTreeTestDb.SeededEquipmentId);

        // Seed has 2 tags (speed=Float, running=Boolean) + 1 vtag (computed).
        // Tags are ordered by Name: "running" < "speed".
        children.Count.ShouldBe(3);

        var running = children[0];
        running.Kind.ShouldBe(UnsNodeKind.Tag);
        running.Key.ShouldBe("tag:TAG-2");
        running.EntityId.ShouldBe("TAG-2");
        running.ClusterId.ShouldBeNull();
        running.DisplayName.ShouldContain("running");
        running.DisplayName.ShouldContain("Boolean");
        running.ChildCount.ShouldBe(0);
        running.HasLazyChildren.ShouldBeFalse();
        running.Children.ShouldBeEmpty();

        var speed = children[1];
        speed.Kind.ShouldBe(UnsNodeKind.Tag);
        speed.Key.ShouldBe("tag:TAG-1");
        speed.EntityId.ShouldBe("TAG-1");
        speed.DisplayName.ShouldContain("speed");
        speed.DisplayName.ShouldContain("Float");

        var vtag = children[2];
        vtag.Kind.ShouldBe(UnsNodeKind.VirtualTag);
        vtag.Key.ShouldBe("vtag:VTAG-1");
        vtag.EntityId.ShouldBe("VTAG-1");
        vtag.ClusterId.ShouldBeNull();
        vtag.DisplayName.ShouldContain("computed");
        vtag.DisplayName.ShouldContain("VirtualTag");
        vtag.ChildCount.ShouldBe(0);
        vtag.HasLazyChildren.ShouldBeFalse();
        vtag.Children.ShouldBeEmpty();
    }

    /// <summary>An equipment with no tags or virtual tags returns an empty list.</summary>
    [Fact]
    public async Task LoadEquipmentChildren_empty_for_equipment_with_none()
    {
        // Use a fresh named store and add an equipment with no tags/vtags.
        var dbName = $"uns-lazy-empty-{Guid.NewGuid():N}";
        UnsTreeTestDb.SeedNamed(dbName);

        // The orphan equipment id is not in the seeded fixture, so just use a novel id.
        const string emptyEquipmentId = "EQ-NO-TAGS";
        var service = new UnsTreeService(UnsTreeTestDb.Factory(dbName));

        var children = await service.LoadEquipmentChildrenAsync(emptyEquipmentId);

        children.ShouldBeEmpty();
    }
}
