// Copyright 2020-2026 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Adapted from server/mqtt.go in the NATS server Go source.

namespace ZB.MOM.NatsNet.Server.Mqtt;

// References to "spec" here are from https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.pdf

/// <summary>
/// MQTT control packet type byte values.
/// Mirrors the <c>mqttPacket*</c> constants in server/mqtt.go.
/// </summary>
internal static class MqttPacket
{
    public const byte Connect    = 0x10;
    public const byte ConnectAck = 0x20;
    public const byte Pub        = 0x30;
    public const byte PubAck     = 0x40;
    public const byte PubRec     = 0x50;
    public const byte PubRel     = 0x60;
    public const byte PubComp    = 0x70;
    public const byte Sub        = 0x80;
    public const byte SubAck     = 0x90;
    public const byte Unsub      = 0xA0;
    public const byte UnsubAck   = 0xB0;
    public const byte Ping       = 0xC0;
    public const byte PingResp   = 0xD0;
    public const byte Disconnect = 0xE0;
    public const byte Mask       = 0xF0;
    public const byte FlagMask   = 0x0F;
}

/// <summary>
/// MQTT CONNECT packet flag byte values.
/// Mirrors the <c>mqttConnFlag*</c> constants in server/mqtt.go.
/// </summary>
internal static class MqttConnectFlag
{
    public const byte Reserved     = 0x01;
    public const byte CleanSession = 0x02;
    public const byte WillFlag     = 0x04;
    public const byte WillQoS      = 0x18;
    public const byte WillRetain   = 0x20;
    public const byte PasswordFlag = 0x40;
    public const byte UsernameFlag = 0x80;
}

/// <summary>
/// MQTT PUBLISH packet flag byte values.
/// Mirrors the <c>mqttPubFlag*</c> and <c>mqttPubQoS*</c> constants in server/mqtt.go.
/// </summary>
internal static class MqttPubFlag
{
    public const byte Retain = 0x01;
    public const byte QoS    = 0x06;
    public const byte Dup    = 0x08;
    public const byte QoS1   = 0x1 << 1;
    public const byte QoS2   = 0x2 << 1;
}

/// <summary>
/// MQTT CONNACK return codes.
/// Mirrors the <c>mqttConnAckRC*</c> constants in server/mqtt.go.
/// </summary>
internal static class MqttConnAckRc
{
    public const byte Accepted             = 0x00;
    public const byte UnacceptableProtocol = 0x01;
    public const byte IdentifierRejected   = 0x02;
    public const byte ServerUnavailable    = 0x03;
    public const byte BadUserOrPassword    = 0x04;
    public const byte NotAuthorized        = 0x05;
    public const byte QoS2WillRejected     = 0x10;
}

/// <summary>
/// Miscellaneous MQTT protocol constants.
/// Mirrors the remaining scalar constants in server/mqtt.go.
/// </summary>
internal static class MqttConst
{
    /// <summary>Maximum control packet payload size (0xFFFFFFF).</summary>
    public const int  MaxPayloadSize      = 0xFFFFFFF;

    /// <summary>MQTT topic level separator character ('/').</summary>
    public const char TopicLevelSep       = '/';

    /// <summary>Single-level wildcard character ('+').</summary>
    public const char SingleLevelWildcard = '+';

    /// <summary>Multi-level wildcard character ('#').</summary>
    public const char MultiLevelWildcard  = '#';

    /// <summary>Reserved topic prefix character ('$').</summary>
    public const char ReservedPrefix      = '$';

    /// <summary>MQTT protocol level byte (v3.1.1 = 0x04).</summary>
    public const byte ProtoLevel          = 0x04;

    /// <summary>SUBACK failure return code (0x80).</summary>
    public const byte SubAckFailure       = 0x80;

    /// <summary>Fixed flags byte in SUBSCRIBE packets (0x02).</summary>
    public const byte SubscribeFlags      = 0x02;

    /// <summary>Fixed flags byte in UNSUBSCRIBE packets (0x02).</summary>
    public const byte UnsubscribeFlags    = 0x02;

    /// <summary>
    /// Suffix appended to the SID of subscriptions created for MQTT '#' wildcard
    /// at the upper level. Mirrors <c>mqttMultiLevelSidSuffix</c>.
    /// </summary>
    public const string MultiLevelSidSuffix = " fwc";

    /// <summary>Initial byte allocation for publish headers (overestimate).</summary>
    public const int InitialPubHeader = 16;

    /// <summary>Default maximum number of pending QoS-1 acks per session.</summary>
    public const int DefaultMaxAckPending = 1024;

    /// <summary>Absolute upper limit on cumulative MaxAckPending across all session subscriptions.</summary>
    public const int MaxAckTotalLimit = 0xFFFF;

    /// <summary>WebSocket path for MQTT connections.</summary>
    public const string WsPath = "/mqtt";

    /// <summary>Marker character for deleted retained messages (used in flag field).</summary>
    public const char RetainedFlagDelMarker = '-';
}

/// <summary>
/// MQTT-internal NATS subject / stream / consumer name constants.
/// Mirrors the string constants in server/mqtt.go that define JetStream stream names,
/// subject prefixes, and JSA reply tokens.
/// </summary>
internal static class MqttTopics
{
    // -------------------------------------------------------------------------
    // Top-level MQTT subject prefix
    // -------------------------------------------------------------------------

    /// <summary>Prefix used for all internal MQTT subjects.</summary>
    public const string Prefix = "$MQTT.";

    /// <summary>
    /// Prefix for NATS subscriptions used as JS consumer delivery subjects.
    /// MQTT clients must not subscribe to subjects starting with this prefix.
    /// </summary>
    public const string SubPrefix = Prefix + "sub.";

    // -------------------------------------------------------------------------
    // JetStream stream names
    // -------------------------------------------------------------------------

    /// <summary>Stream name for MQTT QoS &gt;0 messages on a given account.</summary>
    public const string MsgsStreamName = "$MQTT_msgs";

    /// <summary>Subject prefix for messages in the MQTT messages stream.</summary>
    public const string MsgsStreamSubjectPrefix = Prefix + "msgs.";

    /// <summary>Stream name for MQTT retained messages.</summary>
    public const string RetainedMsgsStreamName = "$MQTT_rmsgs";

    /// <summary>Subject prefix for messages in the retained messages stream.</summary>
    public const string RetainedMsgsStreamSubject = Prefix + "rmsgs.";

    /// <summary>Stream name for MQTT session state.</summary>
    public const string SessStreamName = "$MQTT_sess";

    /// <summary>Subject prefix for session state messages.</summary>
    public const string SessStreamSubjectPrefix = Prefix + "sess.";

    /// <summary>Name prefix used when creating per-account session streams.</summary>
    public const string SessionsStreamNamePrefix = "$MQTT_sess_";

    /// <summary>Stream name for incoming QoS-2 messages.</summary>
    public const string QoS2IncomingMsgsStreamName = "$MQTT_qos2in";

    /// <summary>Subject prefix for incoming QoS-2 messages.</summary>
    public const string QoS2IncomingMsgsStreamSubjectPrefix = Prefix + "qos2.in.";

    /// <summary>Stream name for outgoing MQTT QoS messages (PUBREL).</summary>
    public const string OutStreamName = "$MQTT_out";

    /// <summary>Subject prefix for outgoing MQTT messages.</summary>
    public const string OutSubjectPrefix = Prefix + "out.";

    /// <summary>Subject prefix for PUBREL messages.</summary>
    public const string PubRelSubjectPrefix = Prefix + "out.pubrel.";

    /// <summary>Subject prefix for PUBREL delivery subjects.</summary>
    public const string PubRelDeliverySubjectPrefix = Prefix + "deliver.pubrel.";

    /// <summary>Durable consumer name prefix for PUBREL.</summary>
    public const string PubRelConsumerDurablePrefix = "$MQTT_PUBREL_";

    // -------------------------------------------------------------------------
    // JSA reply subject prefix and token constants
    // -------------------------------------------------------------------------

    /// <summary>Prefix of the reply subject for JS API requests.</summary>
    public const string JsaRepliesPrefix = Prefix + "JSA.";

    // Token position indices within a JSA reply subject.
    public const int JsaIdTokenPos  = 3;
    public const int JsaTokenPos    = 4;
    public const int JsaClientIdPos = 5;

    // JSA operation token values.
    public const string JsaStreamCreate   = "SC";
    public const string JsaStreamUpdate   = "SU";
    public const string JsaStreamLookup   = "SL";
    public const string JsaStreamDel      = "SD";
    public const string JsaConsumerCreate = "CC";
    public const string JsaConsumerLookup = "CL";
    public const string JsaConsumerDel    = "CD";
    public const string JsaMsgStore       = "MS";
    public const string JsaMsgLoad        = "ML";
    public const string JsaMsgDelete      = "MD";
    public const string JsaSessPersist    = "SP";
    public const string JsaRetainedMsgDel = "RD";
    public const string JsaStreamNames    = "SN";

    // -------------------------------------------------------------------------
    // NATS header names injected into re-encoded PUBLISH messages
    // -------------------------------------------------------------------------

    /// <summary>Header that indicates the message originated from MQTT and stores published QoS.</summary>
    public const string NatsHeader = "Nmqtt-Pub";

    /// <summary>Header storing the original MQTT topic for retained messages.</summary>
    public const string NatsRetainedMessageTopic = "Nmqtt-RTopic";

    /// <summary>Header storing the origin of a retained message.</summary>
    public const string NatsRetainedMessageOrigin = "Nmqtt-ROrigin";

    /// <summary>Header storing the flags of a retained message.</summary>
    public const string NatsRetainedMessageFlags = "Nmqtt-RFlags";

    /// <summary>Header storing the source of a retained message.</summary>
    public const string NatsRetainedMessageSource = "Nmqtt-RSource";

    /// <summary>Header indicating a PUBREL message and storing the packet identifier.</summary>
    public const string NatsPubRelHeader = "Nmqtt-PubRel";

    /// <summary>Header storing the original MQTT subject in re-encoded PUBLISH messages.</summary>
    public const string NatsHeaderSubject = "Nmqtt-Subject";

    /// <summary>Header storing the subject mapping in re-encoded PUBLISH messages.</summary>
    public const string NatsHeaderMapped = "Nmqtt-Mapped";

    // -------------------------------------------------------------------------
    // Sparkplug B constants
    // -------------------------------------------------------------------------

    public const string SparkbNBirth = "NBIRTH";
    public const string SparkbDBirth = "DBIRTH";
    public const string SparkbNDeath = "NDEATH";
    public const string SparkbDDeath = "DDEATH";
}
