using AyCode.Core.Loggers;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.Logging;

namespace AyCode.Services.SignalRs;

/// <summary>
/// Extension methods for applying <see cref="AcHubConnectionOptions"/> to
/// a client <see cref="IHubConnectionBuilder"/>, plus the <see cref="AddAcDefaults"/>
/// bundle for consumer-friendly one-line setup (connection + logging bridge).
/// </summary>
public static class AcSignalRConnectionExtensions
{
    /// <summary>
    /// Framework-default builder setup — combines <see cref="AddAcConnection"/> with a
    /// Microsoft.Extensions.Logging bridge to the supplied <see cref="AcLoggerBase"/>.
    /// Consumers typically call this once when constructing the <see cref="IHubConnectionBuilder"/>.
    /// <para>
    /// Equivalent to:
    /// <code>
    /// builder.AddAcConnection(options)
    ///        .ConfigureLogging(l =&gt; { l.SetMinimumLevel(Information); l.AddAcLogger(_ =&gt; logger); });
    /// </code>
    /// </para>
    /// </summary>
    public static IHubConnectionBuilder AddAcDefaults(this IHubConnectionBuilder builder, AcLoggerBase logger, AcHubConnectionOptions connectionOptions)
    {
        return builder
            .AddAcConnection(connectionOptions)
            .ConfigureLogging(logging =>
            {
                logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Information);
                logging.AddAcLogger(_ => logger);
            });
    }

    /// <summary>
    /// Applies <see cref="AcHubConnectionOptions"/> to the builder:
    /// <c>WithUrl</c> (with HttpConnectionOptions), keep-alive, server timeout,
    /// <c>WithAutomaticReconnect</c>, <c>WithStatefulReconnect</c>.
    /// <para>
    /// Nullable properties are skipped when <c>null</c> — the underlying SignalR default is kept.
    /// Combine freely with any other builder extensions before or after this call; the ordering
    /// follows the fluent chain (last write wins for a given setting).
    /// </para>
    /// </summary>
    public static IHubConnectionBuilder AddAcConnection(this IHubConnectionBuilder builder, AcHubConnectionOptions options)
    {
        if (options is null) throw new ArgumentNullException(nameof(options));
        
        if (string.IsNullOrWhiteSpace(options.Url)) throw new ArgumentException("AcHubConnectionOptions.Url must be set.", nameof(options));

        builder.WithUrl(options.Url, http =>
        {
            if (options.Transports.HasValue) http.Transports = options.Transports.Value;
            if (options.TransportMaxBufferSize.HasValue) http.TransportMaxBufferSize = options.TransportMaxBufferSize.Value;
            if (options.ApplicationMaxBufferSize.HasValue) http.ApplicationMaxBufferSize = options.ApplicationMaxBufferSize.Value;
            if (options.CloseTimeout.HasValue) http.CloseTimeout = options.CloseTimeout.Value;
            if (options.SkipNegotiation.HasValue) http.SkipNegotiation = options.SkipNegotiation.Value;
        });

        if (options.KeepAliveInterval.HasValue) builder.WithKeepAliveInterval(options.KeepAliveInterval.Value);
        if (options.ServerTimeout.HasValue) builder.WithServerTimeout(options.ServerTimeout.Value);
        if (options.UseAutomaticReconnect) builder.WithAutomaticReconnect();
        if (options.UseStatefulReconnect) builder.WithStatefulReconnect();

        return builder;
    }
}
