using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Http;
using Microsoft.Extensions.Options;
using ScadaLink.Commons.Interfaces.Services;

namespace ScadaLink.ExternalSystemGateway;

public static class ServiceCollectionExtensions
{
    /// <summary>
    /// Name prefix of the per-system <see cref="System.Net.Http.HttpClient"/> clients
    /// created by <see cref="ExternalSystemClient"/> (<c>ExternalSystem_{systemName}</c>).
    /// </summary>
    internal const string GatewayClientNamePrefix = "ExternalSystem_";

    public static IServiceCollection AddExternalSystemGateway(this IServiceCollection services)
    {
        services.AddOptions<ExternalSystemGatewayOptions>()
            .BindConfiguration("ScadaLink:ExternalSystemGateway");

        services.AddHttpClient();

        // ExternalSystemGateway-013 / -016: wire MaxConcurrentConnectionsPerSystem
        // into the primary handler of the gateway's per-system named clients
        // ("ExternalSystem_{name}") only. The names are created dynamically, so a
        // static AddHttpClient("name") registration is not possible; instead a
        // post-configure on HttpClientFactoryOptions is applied, filtered by the
        // client-name prefix. ConfigureHttpClientDefaults is deliberately NOT used —
        // it is process-global and would replace the primary handler of every
        // HttpClient in the host (e.g. the Notification Service's OAuth2 token
        // client), silently capping and overriding unrelated components.
        services.AddSingleton<IConfigureOptions<HttpClientFactoryOptions>>(sp =>
            new GatewayHttpClientConfigurator(
                sp.GetRequiredService<IOptionsMonitor<ExternalSystemGatewayOptions>>()));

        services.AddScoped<ExternalSystemClient>();
        services.AddScoped<IExternalSystemClient>(sp => sp.GetRequiredService<ExternalSystemClient>());
        services.AddScoped<DatabaseGateway>();
        services.AddScoped<IDatabaseGateway>(sp => sp.GetRequiredService<DatabaseGateway>());

        return services;
    }

    public static IServiceCollection AddExternalSystemGatewayActors(this IServiceCollection services)
    {
        // WP-10: Actor registration happens in AkkaHostedService.
        // Script Execution Actors run on dedicated blocking I/O dispatcher.
        return services;
    }

    /// <summary>
    /// ExternalSystemGateway-016: configures the primary HTTP message handler with the
    /// gateway's <see cref="ExternalSystemGatewayOptions.MaxConcurrentConnectionsPerSystem"/>
    /// cap, but only for the gateway's own named clients
    /// (<see cref="GatewayClientNamePrefix"/>). Clients owned by other host components
    /// are left untouched, so the cap does not leak process-wide.
    /// </summary>
    private sealed class GatewayHttpClientConfigurator
        : IConfigureNamedOptions<HttpClientFactoryOptions>
    {
        private readonly IOptionsMonitor<ExternalSystemGatewayOptions> _options;

        public GatewayHttpClientConfigurator(IOptionsMonitor<ExternalSystemGatewayOptions> options)
        {
            _options = options;
        }

        public void Configure(HttpClientFactoryOptions options)
        {
            // The default (unnamed) client is not a gateway client — do nothing.
        }

        public void Configure(string? name, HttpClientFactoryOptions options)
        {
            if (name == null || !name.StartsWith(GatewayClientNamePrefix, StringComparison.Ordinal))
            {
                return;
            }

            options.HttpMessageHandlerBuilderActions.Add(builder =>
                builder.PrimaryHandler = new SocketsHttpHandler
                {
                    MaxConnectionsPerServer = _options.CurrentValue.MaxConcurrentConnectionsPerSystem,
                });
        }
    }
}
