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

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)
    {
        services.AddSingleton<StoreAndForwardStorage>(sp =>
        {
            var options = sp.GetRequiredService<IOptions<StoreAndForwardOptions>>().Value;
            var logger = sp.GetRequiredService<ILogger<StoreAndForwardStorage>>();
            return new StoreAndForwardStorage(
                $"Data Source={options.SqliteDbPath}",
                logger);
        });

        services.AddSingleton<StoreAndForwardService>(sp =>
        {
            var storage = sp.GetRequiredService<StoreAndForwardStorage>();
            var options = sp.GetRequiredService<IOptions<StoreAndForwardOptions>>().Value;
            var logger = sp.GetRequiredService<ILogger<StoreAndForwardService>>();
            var replication = sp.GetRequiredService<ReplicationService>();
            // Audit Log #23 (M3 Bundle F): 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 pre-M3 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>();
            // StoreAndForward-023: pass null/empty through unchanged — the
            // service constructor normalises it to UnknownSiteSentinel so a
            // host without an IStoreAndForwardSiteContext registration is
            // observable in the central audit log instead of producing a
            // silent empty-string SourceSite.
            var siteId = siteContext?.SiteId ?? string.Empty;
            return new StoreAndForwardService(
                storage,
                options,
                logger,
                replication,
                cachedCallObserver,
                siteId);
        });

        services.AddSingleton<ReplicationService>(sp =>
        {
            var options = sp.GetRequiredService<IOptions<StoreAndForwardOptions>>().Value;
            var logger = sp.GetRequiredService<ILogger<ReplicationService>>();
            return new ReplicationService(options, logger);
        });

        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;
    }
}
