using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Client.Shared.Models;

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

public class ConnectionSettingsTests
{
    /// <summary>Verifies that ConnectionSettings defaults are correct.</summary>
    [Fact]
    public void Defaults_AreCorrect()
    {
        var settings = new ConnectionSettings();

        settings.EndpointUrl.ShouldBe(string.Empty);
        settings.FailoverUrls.ShouldBeNull();
        settings.Username.ShouldBeNull();
        settings.Password.ShouldBeNull();
        settings.SecurityMode.ShouldBe(SecurityMode.None);
        settings.SessionTimeoutSeconds.ShouldBe(60);
        settings.AutoAcceptCertificates.ShouldBeTrue();
        // CertificateStorePath defaults to empty so constructing settings does not
        // touch disk; DefaultApplicationConfigurationFactory resolves the canonical
        // PKI path lazily on first connect (Client.Shared-010).
        settings.CertificateStorePath.ShouldBe(string.Empty);
    }

    /// <summary>Verifies that validation throws on null endpoint URL.</summary>
    [Fact]
    public void Validate_ThrowsOnNullEndpointUrl()
    {
        var settings = new ConnectionSettings { EndpointUrl = null! };
        Should.Throw<ArgumentException>(() => settings.Validate())
            .ParamName.ShouldBe("EndpointUrl");
    }

    /// <summary>Verifies that validation throws on empty endpoint URL.</summary>
    [Fact]
    public void Validate_ThrowsOnEmptyEndpointUrl()
    {
        var settings = new ConnectionSettings { EndpointUrl = "" };
        Should.Throw<ArgumentException>(() => settings.Validate())
            .ParamName.ShouldBe("EndpointUrl");
    }

    /// <summary>Verifies that validation throws on whitespace endpoint URL.</summary>
    [Fact]
    public void Validate_ThrowsOnWhitespaceEndpointUrl()
    {
        var settings = new ConnectionSettings { EndpointUrl = "   " };
        Should.Throw<ArgumentException>(() => settings.Validate())
            .ParamName.ShouldBe("EndpointUrl");
    }

    /// <summary>Verifies that validation throws on zero timeout.</summary>
    [Fact]
    public void Validate_ThrowsOnZeroTimeout()
    {
        var settings = new ConnectionSettings
        {
            EndpointUrl = "opc.tcp://localhost:4840",
            SessionTimeoutSeconds = 0
        };
        Should.Throw<ArgumentException>(() => settings.Validate())
            .ParamName.ShouldBe("SessionTimeoutSeconds");
    }

    /// <summary>Verifies that validation throws on negative timeout.</summary>
    [Fact]
    public void Validate_ThrowsOnNegativeTimeout()
    {
        var settings = new ConnectionSettings
        {
            EndpointUrl = "opc.tcp://localhost:4840",
            SessionTimeoutSeconds = -1
        };
        Should.Throw<ArgumentException>(() => settings.Validate())
            .ParamName.ShouldBe("SessionTimeoutSeconds");
    }

    /// <summary>Verifies that validation throws on timeout above 3600 seconds.</summary>
    [Fact]
    public void Validate_ThrowsOnTimeoutAbove3600()
    {
        var settings = new ConnectionSettings
        {
            EndpointUrl = "opc.tcp://localhost:4840",
            SessionTimeoutSeconds = 3601
        };
        Should.Throw<ArgumentException>(() => settings.Validate())
            .ParamName.ShouldBe("SessionTimeoutSeconds");
    }

    /// <summary>Verifies that validation succeeds with valid settings.</summary>
    [Fact]
    public void Validate_SucceedsWithValidSettings()
    {
        var settings = new ConnectionSettings
        {
            EndpointUrl = "opc.tcp://localhost:4840",
            SessionTimeoutSeconds = 120
        };
        Should.NotThrow(() => settings.Validate());
    }
}