using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using ZB.MOM.WW.LocalDb;
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
using ZB.MOM.WW.ScadaBridge.SiteEventLogging;

namespace ZB.MOM.WW.ScadaBridge.StoreAndForward;

public static class ServiceCollectionExtensions
{
    /// <summary>
    /// Registers Store-and-Forward services including storage, the delivery service, and the replication service.
    /// </summary>
    /// <param name="services">The service collection to register into.</param>
    /// <returns>The same <paramref name="services"/> collection, for chaining.</returns>
    public static IServiceCollection AddStoreAndForward(this IServiceCollection services)
    {
        // The buffer now lives in the consolidated LocalDb database at LocalDb:Path, not
        // at StoreAndForwardOptions.SqliteDbPath — that option survives only as the
        // migrator's source location (Task 8).
        services.AddSingleton<StoreAndForwardStorage>(sp => new StoreAndForwardStorage(
            sp.GetRequiredService<ILocalDb>(),
            sp.GetRequiredService<ILogger<StoreAndForwardStorage>>()));

        services.AddSingleton<StoreAndForwardService>(sp =>
        {
            var storage = sp.GetRequiredService<StoreAndForwardStorage>();
            var options = sp.GetRequiredService<IOptions<StoreAndForwardOptions>>().Value;
            var logger = sp.GetRequiredService<ILogger<StoreAndForwardService>>();
            // Wire the cached-call lifecycle
            // observer + site identity through DI so the S&F retry loop emits
            // per-attempt + terminal telemetry under the same TrackedOperationId
            // the script-thread CachedSubmit row used. Both bindings are
            // optional — when null the legacy retry behaviour is
            // preserved exactly (tests, central nodes without sites, hosts
            // that haven't called AddAuditLog).
            //
            // Site identity is resolved through the optional
            // IStoreAndForwardSiteContext binding (registered by the Host) to
            // avoid a project-reference cycle with HealthMonitoring's
            // ISiteIdentityProvider — HealthMonitoring already references S&F.
            var cachedCallObserver = sp.GetService<ICachedCallLifecycleObserver>();
            var siteContext = sp.GetService<IStoreAndForwardSiteContext>();
            var siteId = siteContext?.SiteId ?? string.Empty;
            // Optional site operational-event log. Resolved through
            // GetService so a host (or test) that has not called
            // AddSiteEventLogging simply gets null and the S&F activity stays
            // a no-op for site-event purposes.
            var siteEventLogger = sp.GetService<ISiteEventLogger>();
            return new StoreAndForwardService(
                storage,
                options,
                logger,
                cachedCallObserver,
                siteId,
                siteEventLogger);
        });

        return services;
    }

    /// <summary>
    /// Registers Store-and-Forward Akka actor bindings. Actor creation is handled by the Host during actor system startup.
    /// </summary>
    /// <param name="services">The service collection to register into.</param>
    /// <returns>The same <paramref name="services"/> collection, for chaining.</returns>
    public static IServiceCollection AddStoreAndForwardActors(this IServiceCollection services)
    {
        // Akka actor registration handled by Host component during actor system startup
        return services;
    }
}
