// MqttNatsClientAdapter wraps an MqttConnection to implement INatsClient,
// enabling MQTT connections to participate in the standard NATS message routing.
// Go reference: mqtt.go — each MQTT connection behaves as a NATS client internally.

using NATS.Server.Auth;
using NATS.Server.Protocol;
using NATS.Server.Subscriptions;
using System.Text;

namespace NATS.Server.Mqtt;

/// <summary>
/// Adapts an <see cref="MqttConnection"/> to the <see cref="INatsClient"/> interface
/// so MQTT clients can be registered in the server's SubList and receive messages
/// through the standard NATS delivery path.
/// </summary>
public sealed class MqttNatsClientAdapter : INatsClient
{
    private readonly MqttConnection _connection;
    private readonly Dictionary<string, Subscription> _subs = new(StringComparer.Ordinal);

    public ulong Id { get; }
    public ClientKind Kind => ClientKind.Client;
    public Account? Account { get; set; }
    public ClientOptions? ClientOpts => null;
    public ClientPermissions? Permissions { get; set; }

    public string MqttClientId => _connection.ClientId;

    public MqttNatsClientAdapter(MqttConnection connection, ulong id)
    {
        _connection = connection;
        Id = id;
    }

    /// <summary>
    /// Delivers a NATS message to this MQTT client by translating the NATS subject
    /// to an MQTT topic and writing a binary PUBLISH packet.
    /// </summary>
    public void SendMessage(string subject, string sid, string? replyTo,
        ReadOnlyMemory<byte> headers, ReadOnlyMemory<byte> payload)
    {
        var mqttTopic = MqttTopicMapper.NatsToMqtt(subject);
        // Fire-and-forget async send; MQTT delivery is best-effort for QoS 0
        _ = _connection.SendBinaryPublishAsync(mqttTopic, payload, qos: 0,
            retain: false, packetId: 0, CancellationToken.None);
    }

    public void SendMessageNoFlush(string subject, string sid, string? replyTo,
        ReadOnlyMemory<byte> headers, ReadOnlyMemory<byte> payload)
    {
        // MQTT has no concept of deferred flush — deliver immediately
        SendMessage(subject, sid, replyTo, headers, payload);
    }

    public void SignalFlush()
    {
        // No-op for MQTT — each packet is written and flushed immediately
    }

    public bool QueueOutbound(ReadOnlyMemory<byte> data)
    {
        // No-op for MQTT — binary framing, not raw NATS protocol bytes
        return true;
    }

    public void RemoveSubscription(string sid)
    {
        if (_subs.Remove(sid, out var sub))
        {
            Account?.SubList.Remove(sub);
            Account?.DecrementSubscriptions();
        }
    }

    /// <summary>
    /// Creates a NATS subscription for an MQTT topic filter and inserts it into
    /// the account's SubList so NATS messages are delivered to this MQTT client.
    /// </summary>
    public Subscription AddSubscription(string natsSubject, string sid, string? queue = null)
    {
        var sub = new Subscription
        {
            Client = this,
            Subject = natsSubject,
            Sid = sid,
            Queue = queue,
        };
        _subs[sid] = sub;

        Account?.SubList.Insert(sub);
        Account?.IncrementSubscriptions();
        return sub;
    }

    /// <summary>
    /// Removes all subscriptions for this adapter from the SubList.
    /// Called during connection cleanup.
    /// </summary>
    public void RemoveAllSubscriptions()
    {
        foreach (var sub in _subs.Values)
        {
            Account?.SubList.Remove(sub);
        }

        _subs.Clear();
    }

    public IReadOnlyDictionary<string, Subscription> Subscriptions => _subs;
}
