using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;

namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests;

/// <summary>
///     Scaffold tests for <c>ISubscribable</c> + <c>IHostConnectivityProbe</c> that don't
///     need a live remote server. Live-session tests (subscribe/unsubscribe round-trip,
///     keep-alive transitions) land in a follow-up PR once the in-process OPC UA server
///     fixture is scaffolded.
/// </summary>
[Trait("Category", "Unit")]
public sealed class OpcUaClientSubscribeAndProbeTests
{
    /// <summary>Verifies that subscribe without initialization throws InvalidOperationException.</summary>
    [Fact]
    public async Task SubscribeAsync_without_initialize_throws_InvalidOperationException()
    {
        using var drv = new OpcUaClientDriver(new OpcUaClientDriverOptions(), "opcua-sub-uninit");
        await Should.ThrowAsync<InvalidOperationException>(async () =>
            await drv.SubscribeAsync(["ns=2;s=Demo"], TimeSpan.FromMilliseconds(100), TestContext.Current.CancellationToken));
    }

    /// <summary>Verifies that unsubscribe with unknown handle is a no-op.</summary>
    [Fact]
    public async Task UnsubscribeAsync_with_unknown_handle_is_noop()
    {
        using var drv = new OpcUaClientDriver(new OpcUaClientDriverOptions(), "opcua-sub-unknown");
        // UnsubscribeAsync returns cleanly for handles it doesn't recognise — protects against
        // the caller's race with server-side cleanup after a session drop.
        await drv.UnsubscribeAsync(new FakeHandle(), TestContext.Current.CancellationToken);
    }

    /// <summary>Verifies that GetHostStatuses returns endpoint URL row before initialization.</summary>
    [Fact]
    public void GetHostStatuses_returns_endpoint_url_row_pre_init()
    {
        using var drv = new OpcUaClientDriver(
            new OpcUaClientDriverOptions { EndpointUrl = "opc.tcp://plc.example:4840" },
            "opcua-hosts");
        var rows = drv.GetHostStatuses();
        rows.Count.ShouldBe(1);
        rows[0].HostName.ShouldBe("opc.tcp://plc.example:4840",
            "host identity mirrors the endpoint URL so the Admin /hosts dashboard can link back to the remote server");
        rows[0].State.ShouldBe(HostState.Unknown);
    }

    /// <summary>A fake subscription handle for testing.</summary>
    private sealed class FakeHandle : ISubscriptionHandle
    {
        /// <inheritdoc />
        public string DiagnosticId => "fake";
    }
}
