using System.Text;

namespace NATS.Server.Gateways;

/// <summary>
/// Gateway wire protocol command types matching Go's gateway.go format.
/// Go reference: gateway.go:90-120 — gateway protocol constants.
/// </summary>
public enum GatewayCommandType
{
    /// <summary>Gateway connection info exchange.</summary>
    Info,
    /// <summary>Subscribe interest notification.</summary>
    Sub,
    /// <summary>Unsubscribe interest notification.</summary>
    Unsub,
    /// <summary>Account interest mode change.</summary>
    Mode,
    /// <summary>Routed message through gateway.</summary>
    Msg,
    /// <summary>Ping keepalive.</summary>
    Ping,
    /// <summary>Pong keepalive response.</summary>
    Pong,
}

/// <summary>
/// Gateway wire protocol byte sequences and formatting helpers matching Go's gateway protocol.
/// Go reference: gateway.go:90-120 — gateway protocol constants and command formatting.
/// </summary>
public static class GatewayCommands
{
    // Wire format byte sequences matching Go's gateway protocol
    public static readonly byte[] InfoPrefix = "GINFO "u8.ToArray();
    public static readonly byte[] SubPrefix = "GS+ "u8.ToArray();
    public static readonly byte[] UnsubPrefix = "GS- "u8.ToArray();
    public static readonly byte[] ModePrefix = "GMODE "u8.ToArray();
    public static readonly byte[] MsgPrefix = "GMSG "u8.ToArray();
    public static readonly byte[] Ping = "GPING\r\n"u8.ToArray();
    public static readonly byte[] Pong = "GPONG\r\n"u8.ToArray();
    public static readonly byte[] Crlf = "\r\n"u8.ToArray();

    /// <summary>
    /// Formats a gateway subscribe command.
    /// Wire format: GS+ {account} {subject}\r\n
    /// Go reference: gateway.go — sendGatewaySubsToGateway, RS+ propagation.
    /// </summary>
    public static byte[] FormatSub(string account, string subject)
        => Encoding.UTF8.GetBytes($"GS+ {account} {subject}\r\n");

    /// <summary>
    /// Formats a gateway unsubscribe command.
    /// Wire format: GS- {account} {subject}\r\n
    /// Go reference: gateway.go — sendGatewayUnsubToGateway, RS- propagation.
    /// </summary>
    public static byte[] FormatUnsub(string account, string subject)
        => Encoding.UTF8.GetBytes($"GS- {account} {subject}\r\n");

    /// <summary>
    /// Formats a gateway mode change command.
    /// Wire format: GMODE {account} {mode}\r\n
    /// Mode: "O" for Optimistic (send everything), "I" for Interest-only.
    /// Go reference: gateway.go — switchAccountToInterestMode, GMODE command.
    /// </summary>
    public static byte[] FormatMode(string account, GatewayInterestMode mode)
    {
        var modeStr = mode == GatewayInterestMode.InterestOnly ? "I" : "O";
        return Encoding.UTF8.GetBytes($"GMODE {account} {modeStr}\r\n");
    }

    /// <summary>
    /// Parses a gateway command type from the first bytes of a line.
    /// Returns null if the command prefix is unrecognized.
    /// Go reference: gateway.go — processGatewayMsg command dispatch.
    /// </summary>
    public static GatewayCommandType? ParseCommandType(ReadOnlySpan<byte> line)
    {
        if (line.StartsWith(InfoPrefix)) return GatewayCommandType.Info;
        if (line.StartsWith(SubPrefix)) return GatewayCommandType.Sub;
        if (line.StartsWith(UnsubPrefix)) return GatewayCommandType.Unsub;
        if (line.StartsWith(ModePrefix)) return GatewayCommandType.Mode;
        if (line.StartsWith(MsgPrefix)) return GatewayCommandType.Msg;
        if (line.StartsWith(Ping)) return GatewayCommandType.Ping;
        if (line.StartsWith(Pong)) return GatewayCommandType.Pong;
        return null;
    }
}
