namespace NATS.Server.JetStream.Api;

/// <summary>
/// Publishes JetStream advisory events to $JS.EVENT.ADVISORY.* subjects.
/// Designed to be lightweight and testable; accepts a publish action delegate
/// rather than depending directly on InternalEventSystem.
/// Go reference: jetstream_api.go advisory publication.
/// </summary>
public sealed class AdvisoryPublisher
{
    private readonly Action<string, object> _publishAction;
    private long _publishCount;

    public AdvisoryPublisher(Action<string, object> publishAction)
    {
        _publishAction = publishAction;
    }

    /// <summary>
    /// Total number of advisory events published since creation.
    /// </summary>
    public long PublishCount => Interlocked.Read(ref _publishCount);

    /// <summary>
    /// Publishes a stream created advisory.
    /// Go reference: jetstream_api.go — advisory on stream creation.
    /// </summary>
    public void StreamCreated(string streamName, object? detail = null)
    {
        var subject = string.Format(Events.EventSubjects.JsAdvisoryStreamCreated, streamName);
        Publish(subject, new AdvisoryEvent
        {
            Type = "io.nats.jetstream.advisory.stream_created",
            Stream = streamName,
            TimeStamp = DateTime.UtcNow,
            Detail = detail,
        });
    }

    /// <summary>
    /// Publishes a stream deleted advisory.
    /// Go reference: jetstream_api.go — advisory on stream deletion.
    /// </summary>
    public void StreamDeleted(string streamName)
    {
        var subject = string.Format(Events.EventSubjects.JsAdvisoryStreamDeleted, streamName);
        Publish(subject, new AdvisoryEvent
        {
            Type = "io.nats.jetstream.advisory.stream_deleted",
            Stream = streamName,
            TimeStamp = DateTime.UtcNow,
        });
    }

    /// <summary>
    /// Publishes a stream updated advisory.
    /// Go reference: jetstream_api.go — advisory on stream config update.
    /// </summary>
    public void StreamUpdated(string streamName, object? detail = null)
    {
        var subject = string.Format(Events.EventSubjects.JsAdvisoryStreamUpdated, streamName);
        Publish(subject, new AdvisoryEvent
        {
            Type = "io.nats.jetstream.advisory.stream_updated",
            Stream = streamName,
            TimeStamp = DateTime.UtcNow,
            Detail = detail,
        });
    }

    /// <summary>
    /// Publishes a consumer created advisory.
    /// Go reference: jetstream_api.go — advisory on consumer creation.
    /// </summary>
    public void ConsumerCreated(string streamName, string consumerName)
    {
        var subject = string.Format(Events.EventSubjects.JsAdvisoryConsumerCreated, streamName, consumerName);
        Publish(subject, new AdvisoryEvent
        {
            Type = "io.nats.jetstream.advisory.consumer_created",
            Stream = streamName,
            Consumer = consumerName,
            TimeStamp = DateTime.UtcNow,
        });
    }

    /// <summary>
    /// Publishes a consumer deleted advisory.
    /// Go reference: jetstream_api.go — advisory on consumer deletion.
    /// </summary>
    public void ConsumerDeleted(string streamName, string consumerName)
    {
        var subject = string.Format(Events.EventSubjects.JsAdvisoryConsumerDeleted, streamName, consumerName);
        Publish(subject, new AdvisoryEvent
        {
            Type = "io.nats.jetstream.advisory.consumer_deleted",
            Stream = streamName,
            Consumer = consumerName,
            TimeStamp = DateTime.UtcNow,
        });
    }

    private void Publish(string subject, AdvisoryEvent evt)
    {
        Interlocked.Increment(ref _publishCount);
        _publishAction(subject, evt);
    }
}

/// <summary>
/// Advisory event payload describing a JetStream lifecycle event.
/// Go reference: jetstream_api.go advisory event types.
/// </summary>
public sealed class AdvisoryEvent
{
    /// <summary>Reverse-DNS event type identifier (e.g., "io.nats.jetstream.advisory.stream_created").</summary>
    public string Type { get; init; } = string.Empty;

    /// <summary>Name of the stream involved in the event, if applicable.</summary>
    public string? Stream { get; init; }

    /// <summary>Name of the consumer involved in the event, if applicable.</summary>
    public string? Consumer { get; init; }

    /// <summary>UTC timestamp when the advisory was generated.</summary>
    public DateTime TimeStamp { get; init; }

    /// <summary>Optional additional detail payload (arbitrary object).</summary>
    public object? Detail { get; init; }
}
