using Microsoft.Extensions.DependencyInjection;
using ScadaLink.NotificationOutbox.Delivery;

namespace ScadaLink.NotificationOutbox;

/// <summary>
/// DI registration for the Notification Outbox component: binds
/// <see cref="NotificationOutboxOptions"/> and registers the channel delivery adapters.
/// </summary>
public static class ServiceCollectionExtensions
{
    /// <summary>Configuration section bound to <see cref="NotificationOutboxOptions"/>.</summary>
    public const string OptionsSection = "ScadaLink:NotificationOutbox";

    /// <summary>
    /// Registers the Notification Outbox services: the <see cref="NotificationOutboxOptions"/>
    /// binding and the channel delivery adapters.
    ///
    /// This extension covers only the outbox-specific registrations. The
    /// <see cref="EmailNotificationDeliveryAdapter"/> reuses the
    /// <see cref="ScadaLink.NotificationService"/> SMTP machinery —
    /// <c>Func&lt;ISmtpClientWrapper&gt;</c>, <c>OAuth2TokenService</c> and
    /// <c>NotificationOptions</c> — so the caller (the Host on the central node) must also
    /// call <c>AddNotificationService()</c>. Re-registering those services here would
    /// duplicate them; relying on <c>AddNotificationService</c> keeps a single source of truth.
    ///
    /// <see cref="EmailNotificationDeliveryAdapter"/> is registered <em>scoped</em> because it
    /// takes a scoped <see cref="ScadaLink.Commons.Interfaces.Repositories.INotificationRepository"/>
    /// directly. The <see cref="NotificationOutboxActor"/> resolves the adapters from a fresh
    /// scope per dispatch sweep rather than holding them, so no scoped adapter is captured by
    /// the singleton actor.
    /// </summary>
    public static IServiceCollection AddNotificationOutbox(this IServiceCollection services)
    {
        ArgumentNullException.ThrowIfNull(services);

        services.AddOptions<NotificationOutboxOptions>()
            .BindConfiguration(OptionsSection);

        // Scoped: the adapter holds a scoped INotificationRepository. Registered both under
        // the interface (so the dispatch sweep can enumerate every channel adapter) and as
        // the concrete type (so callers and tests can resolve it directly).
        services.AddScoped<EmailNotificationDeliveryAdapter>();
        services.AddScoped<INotificationDeliveryAdapter>(
            sp => sp.GetRequiredService<EmailNotificationDeliveryAdapter>());

        return services;
    }
}
