using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;

namespace ZB.MOM.WW.ScadaBridge.HealthMonitoring;

public static class ServiceCollectionExtensions
{
    /// <summary>
    /// Register site-side health monitoring services (metric collection + periodic reporting).
    /// Call this on site nodes only. For central, call AddCentralHealthAggregation() instead.
    /// </summary>
    /// <param name="services">The DI service collection to register into.</param>
    /// <returns>The same <paramref name="services"/> instance, for call chaining.</returns>
    public static IServiceCollection AddSiteHealthMonitoring(this IServiceCollection services)
    {
        AddOptionsValidation(services);
        services.AddSingleton<ISiteHealthCollector, SiteHealthCollector>();
        services.AddHostedService<HealthReportSender>();
        return services;
    }

    /// <summary>
    /// Register shared health monitoring services (safe for both central and site).
    /// Does not start the HealthReportSender — call AddSiteHealthMonitoring() on site nodes for that.
    /// </summary>
    /// <param name="services">The DI service collection to register into.</param>
    /// <returns>The same <paramref name="services"/> instance, for call chaining.</returns>
    public static IServiceCollection AddHealthMonitoring(this IServiceCollection services)
    {
        AddOptionsValidation(services);
        services.AddSingleton<ISiteHealthCollector, SiteHealthCollector>();
        return services;
    }

    /// <summary>
    /// Register central-side health aggregation services. Includes the
    /// <see cref="CentralHealthReportLoop"/> that generates a self-report
    /// for the central cluster so it appears on /monitoring/health.
    /// </summary>
    /// <param name="services">The DI service collection to register into.</param>
    /// <returns>The same <paramref name="services"/> instance, for call chaining.</returns>
    public static IServiceCollection AddCentralHealthAggregation(this IServiceCollection services)
    {
        AddOptionsValidation(services);
        services.AddSingleton<CentralHealthAggregator>();
        services.AddSingleton<ICentralHealthAggregator>(sp => sp.GetRequiredService<CentralHealthAggregator>());
        services.AddHostedService(sp => sp.GetRequiredService<CentralHealthAggregator>());
        services.AddHostedService<CentralHealthReportLoop>();
        return services;
    }

    /// <summary>
    /// HealthMonitoring-014: register the <see cref="HealthMonitoringOptionsValidator"/>
    /// so a misconfigured <c>ScadaBridge:HealthMonitoring</c> section (zero/negative
    /// intervals, or a <c>CentralOfflineTimeout</c> shorter than
    /// <c>OfflineTimeout</c>) is rejected with a clear, key-naming message when the
    /// hosted services resolve their options at startup — rather than crashing
    /// later inside a <see cref="PeriodicTimer"/> constructor with an opaque
    /// <see cref="ArgumentOutOfRangeException"/>. Idempotent so it is safe when
    /// more than one of the registration methods above is called.
    /// </summary>
    private static void AddOptionsValidation(IServiceCollection services)
    {
        services.TryAddEnumerable(
            ServiceDescriptor.Singleton<IValidateOptions<HealthMonitoringOptions>, HealthMonitoringOptionsValidator>());
    }
}
