using NATS.Server.Auth;

namespace NATS.Server.Core.Tests;

public class InternalClientTests
{
    [Theory]
    [InlineData(ClientKind.Client, false)]
    [InlineData(ClientKind.Router, false)]
    [InlineData(ClientKind.Gateway, false)]
    [InlineData(ClientKind.Leaf, false)]
    [InlineData(ClientKind.System, true)]
    [InlineData(ClientKind.JetStream, true)]
    [InlineData(ClientKind.Account, true)]
    public void IsInternal_returns_correct_value(ClientKind kind, bool expected)
    {
        kind.IsInternal().ShouldBe(expected);
    }

    [Fact]
    public void NatsClient_implements_INatsClient()
    {
        typeof(NatsClient).GetInterfaces().ShouldContain(typeof(INatsClient));
    }

    [Fact]
    public void NatsClient_kind_is_Client()
    {
        typeof(NatsClient).GetProperty("Kind")!.PropertyType.ShouldBe(typeof(ClientKind));
    }

    [Fact]
    public void InternalClient_system_kind()
    {
        var account = new Account("$SYS");
        var client = new InternalClient(1, ClientKind.System, account);
        client.Kind.ShouldBe(ClientKind.System);
        client.IsInternal.ShouldBeTrue();
        client.Id.ShouldBe(1UL);
        client.Account.ShouldBe(account);
    }

    [Fact]
    public void InternalClient_account_kind()
    {
        var account = new Account("myaccount");
        var client = new InternalClient(2, ClientKind.Account, account);
        client.Kind.ShouldBe(ClientKind.Account);
        client.IsInternal.ShouldBeTrue();
    }

    [Fact]
    public void InternalClient_rejects_non_internal_kind()
    {
        var account = new Account("test");
        Should.Throw<ArgumentException>(() => new InternalClient(1, ClientKind.Client, account));
    }

    [Fact]
    public void InternalClient_SendMessage_invokes_callback()
    {
        var account = new Account("$SYS");
        var client = new InternalClient(1, ClientKind.System, account);
        string? capturedSubject = null;
        string? capturedSid = null;
        client.MessageCallback = (subject, sid, replyTo, headers, payload) =>
        {
            capturedSubject = subject;
            capturedSid = sid;
        };

        client.SendMessage("test.subject", "1", null, ReadOnlyMemory<byte>.Empty, ReadOnlyMemory<byte>.Empty);

        capturedSubject.ShouldBe("test.subject");
        capturedSid.ShouldBe("1");
    }

    [Fact]
    public void InternalClient_QueueOutbound_returns_true_noop()
    {
        var account = new Account("$SYS");
        var client = new InternalClient(1, ClientKind.System, account);
        client.QueueOutbound(ReadOnlyMemory<byte>.Empty).ShouldBeTrue();
    }
}
