using System;
using System.Collections.Generic;
namespace Svrnty.CQRS.Events.Abstractions.Configuration;
///
/// Configuration for external event delivery to cross-service message brokers.
///
///
/// This configuration is used to specify how events from a stream should be
/// published externally to other services via message brokers like RabbitMQ or Kafka.
///
public sealed class ExternalDeliveryConfiguration
{
///
/// Gets or sets whether external delivery is enabled for this stream.
///
///
/// Default: false (events remain internal to the service).
///
public bool Enabled { get; set; } = false;
///
/// Gets or sets the provider type to use for external delivery.
///
///
/// Supported values: "RabbitMQ", "Kafka", "AzureServiceBus", "AwsSns"
/// Default: null (must be specified if Enabled = true)
///
public string? ProviderType { get; set; }
///
/// Gets or sets the connection string for the external message broker.
///
///
/// RabbitMQ: amqp://user:pass@localhost:5672/vhost
/// Kafka: localhost:9092
/// Azure Service Bus: Endpoint=sb://...;SharedAccessKey=...
///
public string? ConnectionString { get; set; }
///
/// Gets or sets the exchange name (RabbitMQ) or topic name (Kafka).
///
///
/// If not specified, defaults to the stream name.
/// Example: "user-service.events" or "orders.events"
///
public string? ExchangeName { get; set; }
///
/// Gets or sets the exchange type for RabbitMQ.
///
///
/// Supported values: "topic", "fanout", "direct", "headers"
/// Default: "topic" (recommended for most scenarios)
///
public string ExchangeType { get; set; } = "topic";
///
/// Gets or sets the routing key strategy for RabbitMQ.
///
///
/// Supported strategies:
///
/// - EventTypeRoute by event type name (e.g., "UserCreatedEvent")
/// - StreamNameRoute by stream name (e.g., "user-events")
/// - CustomUse custom routing key from metadata
/// - WildcardRoute to all consumers (use "*" routing key)
///
/// Default: "EventType"
///
public string RoutingKeyStrategy { get; set; } = "EventType";
///
/// Gets or sets whether to automatically declare/create the exchange and queues.
///
///
/// Default: true (recommended for development).
/// Set to false in production if topology is managed externally.
///
public bool AutoDeclareTopology { get; set; } = true;
///
/// Gets or sets whether messages should be persistent (survive broker restart).
///
///
/// Default: true (durable messages).
/// Set to false for fire-and-forget scenarios where message loss is acceptable.
///
public bool Persistent { get; set; } = true;
///
/// Gets or sets the maximum number of retry attempts for failed publishes.
///
///
/// Default: 3
/// Set to 0 to disable retries.
///
public int MaxRetries { get; set; } = 3;
///
/// Gets or sets the delay between retry attempts.
///
///
/// Default: 1 second
/// Exponential backoff is applied (delay * 2^attemptNumber).
///
public TimeSpan RetryDelay { get; set; } = TimeSpan.FromSeconds(1);
///
/// Gets or sets additional provider-specific settings.
///
///
/// This allows passing custom configuration to specific providers without
/// changing the core configuration model.
///
public Dictionary AdditionalSettings { get; set; } = new();
///
/// Validates the configuration.
///
/// Thrown if the configuration is invalid.
public void Validate()
{
if (!Enabled)
return;
if (string.IsNullOrWhiteSpace(ProviderType))
throw new InvalidOperationException("ProviderType must be specified when external delivery is enabled.");
if (string.IsNullOrWhiteSpace(ConnectionString))
throw new InvalidOperationException("ConnectionString must be specified when external delivery is enabled.");
if (MaxRetries < 0)
throw new InvalidOperationException("MaxRetries cannot be negative.");
if (RetryDelay <= TimeSpan.Zero)
throw new InvalidOperationException("RetryDelay must be positive.");
var validExchangeTypes = new[] { "topic", "fanout", "direct", "headers" };
if (!validExchangeTypes.Contains(ExchangeType.ToLowerInvariant()))
throw new InvalidOperationException($"ExchangeType must be one of: {string.Join(", ", validExchangeTypes)}");
var validRoutingStrategies = new[] { "EventType", "StreamName", "Custom", "Wildcard" };
if (!validRoutingStrategies.Contains(RoutingKeyStrategy))
throw new InvalidOperationException($"RoutingKeyStrategy must be one of: {string.Join(", ", validRoutingStrategies)}");
}
}