using Opc.Ua;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
using BrowseResult = ZB.MOM.WW.OtOpcUa.Client.Shared.Models.BrowseResult;

namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Tests.Models;

public class ModelConstructionTests
{
    [Fact]
    public void BrowseResult_ConstructsCorrectly()
    {
        var result = new BrowseResult("ns=2;s=MyNode", "MyNode", "Variable", true);

        result.NodeId.ShouldBe("ns=2;s=MyNode");
        result.DisplayName.ShouldBe("MyNode");
        result.NodeClass.ShouldBe("Variable");
        result.HasChildren.ShouldBeTrue();
    }

    [Fact]
    public void BrowseResult_WithoutChildren()
    {
        var result = new BrowseResult("ns=2;s=Leaf", "Leaf", "Variable", false);
        result.HasChildren.ShouldBeFalse();
    }

    [Fact]
    public void AlarmEventArgs_ConstructsCorrectly()
    {
        var time = new DateTime(2026, 1, 15, 10, 30, 0, DateTimeKind.Utc);
        var args = new AlarmEventArgs("Source1", "HighTemp", 500, "Temperature high", true, true, false, time);

        args.SourceName.ShouldBe("Source1");
        args.ConditionName.ShouldBe("HighTemp");
        args.Severity.ShouldBe((ushort)500);
        args.Message.ShouldBe("Temperature high");
        args.Retain.ShouldBeTrue();
        args.ActiveState.ShouldBeTrue();
        args.AckedState.ShouldBeFalse();
        args.Time.ShouldBe(time);
    }

    [Fact]
    public void RedundancyInfo_ConstructsCorrectly()
    {
        var uris = new[] { "urn:server1", "urn:server2" };
        var info = new RedundancyInfo("Warm", 200, uris, "urn:server1");

        info.Mode.ShouldBe("Warm");
        info.ServiceLevel.ShouldBe((byte)200);
        info.ServerUris.ShouldBe(uris);
        info.ApplicationUri.ShouldBe("urn:server1");
    }

    [Fact]
    public void RedundancyInfo_WithEmptyUris()
    {
        var info = new RedundancyInfo("None", 0, [], string.Empty);
        info.ServerUris.ShouldBeEmpty();
        info.ApplicationUri.ShouldBeEmpty();
    }

    [Fact]
    public void DataChangedEventArgs_ConstructsCorrectly()
    {
        var value = new DataValue(new Variant(42), StatusCodes.Good);
        var args = new DataChangedEventArgs("ns=2;s=Temp", value);

        args.NodeId.ShouldBe("ns=2;s=Temp");
        args.Value.ShouldBe(value);
        args.Value.Value.ShouldBe(42);
    }

    [Fact]
    public void ConnectionStateChangedEventArgs_ConstructsCorrectly()
    {
        var args = new ConnectionStateChangedEventArgs(
            ConnectionState.Disconnected, ConnectionState.Connected, "opc.tcp://localhost:4840");

        args.OldState.ShouldBe(ConnectionState.Disconnected);
        args.NewState.ShouldBe(ConnectionState.Connected);
        args.EndpointUrl.ShouldBe("opc.tcp://localhost:4840");
    }

    [Fact]
    public void ConnectionInfo_ConstructsCorrectly()
    {
        var info = new ConnectionInfo(
            "opc.tcp://localhost:4840",
            "TestServer",
            "None",
            "http://opcfoundation.org/UA/SecurityPolicy#None",
            "ns=0;i=12345",
            "TestSession");

        info.EndpointUrl.ShouldBe("opc.tcp://localhost:4840");
        info.ServerName.ShouldBe("TestServer");
        info.SecurityMode.ShouldBe("None");
        info.SecurityPolicyUri.ShouldBe("http://opcfoundation.org/UA/SecurityPolicy#None");
        info.SessionId.ShouldBe("ns=0;i=12345");
        info.SessionName.ShouldBe("TestSession");
    }

    [Fact]
    public void SecurityMode_Enum_HasExpectedValues()
    {
        Enum.GetValues<SecurityMode>().Length.ShouldBe(3);
        ((int)SecurityMode.None).ShouldBe(0);
        ((int)SecurityMode.Sign).ShouldBe(1);
        ((int)SecurityMode.SignAndEncrypt).ShouldBe(2);
    }

    [Fact]
    public void ConnectionState_Enum_HasExpectedValues()
    {
        Enum.GetValues<ConnectionState>().Length.ShouldBe(4);
        ((int)ConnectionState.Disconnected).ShouldBe(0);
        ((int)ConnectionState.Connecting).ShouldBe(1);
        ((int)ConnectionState.Connected).ShouldBe(2);
        ((int)ConnectionState.Reconnecting).ShouldBe(3);
    }

    [Fact]
    public void AggregateType_Enum_HasExpectedValues()
    {
        Enum.GetValues<AggregateType>().Length.ShouldBe(7);
    }
}