using System.Text;
using NATS.Server.Gateways;
using Shouldly;

namespace NATS.Server.Gateways.Tests.Gateways;

// Go reference: gateway.go:90-120 — gateway protocol constants and command formatting.

public class GatewayCommandTests
{
    [Fact]
    public void FormatSub_produces_correct_wire_format()
    {
        // Go reference: gateway.go — RS+ propagation, sendGatewaySubsToGateway
        var bytes = GatewayCommands.FormatSub("$G", "orders.>");
        var line = Encoding.UTF8.GetString(bytes);
        line.ShouldBe("GS+ $G orders.>\r\n");
    }

    [Fact]
    public void FormatUnsub_produces_correct_wire_format()
    {
        // Go reference: gateway.go — RS- propagation, sendGatewayUnsubToGateway
        var bytes = GatewayCommands.FormatUnsub("$G", "orders.>");
        var line = Encoding.UTF8.GetString(bytes);
        line.ShouldBe("GS- $G orders.>\r\n");
    }

    [Fact]
    public void FormatMode_optimistic_produces_O()
    {
        // Go reference: gateway.go — GMODE command, "O" = Optimistic mode
        var bytes = GatewayCommands.FormatMode("$G", GatewayInterestMode.Optimistic);
        var line = Encoding.UTF8.GetString(bytes);
        line.ShouldBe("GMODE $G O\r\n");
    }

    [Fact]
    public void FormatMode_interest_only_produces_I()
    {
        // Go reference: gateway.go — GMODE command, "I" = InterestOnly mode
        var bytes = GatewayCommands.FormatMode("$G", GatewayInterestMode.InterestOnly);
        var line = Encoding.UTF8.GetString(bytes);
        line.ShouldBe("GMODE $G I\r\n");
    }

    [Fact]
    public void ParseCommandType_identifies_sub()
    {
        // Go reference: gateway.go — processGatewayMsg dispatch on GS+
        var line = Encoding.UTF8.GetBytes("GS+ ACC foo.bar\r\n");
        var result = GatewayCommands.ParseCommandType(line);
        result.ShouldBe(GatewayCommandType.Sub);
    }

    [Fact]
    public void ParseCommandType_identifies_unsub()
    {
        // Go reference: gateway.go — processGatewayMsg dispatch on GS-
        var line = Encoding.UTF8.GetBytes("GS- ACC foo.bar\r\n");
        var result = GatewayCommands.ParseCommandType(line);
        result.ShouldBe(GatewayCommandType.Unsub);
    }

    [Fact]
    public void ParseCommandType_identifies_ping()
    {
        // Go reference: gateway.go — keepalive GPING command
        var result = GatewayCommands.ParseCommandType(GatewayCommands.Ping);
        result.ShouldBe(GatewayCommandType.Ping);
    }

    [Fact]
    public void ParseCommandType_identifies_pong()
    {
        // Go reference: gateway.go — keepalive GPONG response
        var result = GatewayCommands.ParseCommandType(GatewayCommands.Pong);
        result.ShouldBe(GatewayCommandType.Pong);
    }

    [Fact]
    public void ParseCommandType_returns_null_for_unknown()
    {
        // Unrecognized commands should return null for graceful handling
        var line = Encoding.UTF8.GetBytes("UNKNOWN something\r\n");
        var result = GatewayCommands.ParseCommandType(line);
        result.ShouldBeNull();
    }

    [Fact]
    public void Wire_format_constants_end_correctly()
    {
        // Go reference: gateway.go — all gateway commands use CRLF line endings
        var crlf = new byte[] { (byte)'\r', (byte)'\n' };
        GatewayCommands.Ping.TakeLast(2).ShouldBe(crlf);
        GatewayCommands.Pong.TakeLast(2).ShouldBe(crlf);
        GatewayCommands.Crlf.ShouldBe(crlf);
    }
}
