using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

namespace AyCode.Core.Loggers;

/// <summary>
/// DI extension methods for the <see cref="AcLoggerBase"/> factory pattern.
/// <para>
/// Consumers call one of the <c>AddAcLoggerFactory</c> overloads after
/// <c>services.Configure&lt;AcLoggerOptions&gt;(...)</c> to register a
/// <see cref="Func{String, AcLoggerBase}"/> singleton that produces category-scoped
/// logger instances with DI-resolved writers.
/// </para>
/// </summary>
public static class AcLoggerServiceExtensions
{
    /// <summary>
    /// Registers a logger factory creating <typeparamref name="TLogger"/> instances per caller category.
    /// Writers are resolved from DI via <see cref="IAcLogWriterBase"/> (all registered writers are included).
    /// </summary>
    /// <typeparam name="TLogger">
    /// Concrete logger type. Must expose a public constructor with signature
    /// <c>(AppType, LogLevel, string?, params IAcLogWriterBase[])</c>.
    /// </typeparam>
    public static IServiceCollection AddAcLoggerFactory<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TLogger>(
        this IServiceCollection services)
        where TLogger : AcLoggerBase
    {
        return services.AddAcLoggerFactory<TLogger, IAcLogWriterBase>();
    }

    /// <summary>
    /// Registers a logger factory with a custom writer marker interface — e.g. a client-only marker
    /// to keep server-only and client-only writers separated at the DI level.
    /// </summary>
    /// <typeparam name="TLogger">Concrete logger type. See <see cref="AddAcLoggerFactory{TLogger}"/> for ctor requirements.</typeparam>
    /// <typeparam name="TWriterBase">Writer marker interface; must extend <see cref="IAcLogWriterBase"/>.</typeparam>
    public static IServiceCollection AddAcLoggerFactory<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TLogger, TWriterBase>(
        this IServiceCollection services)
        where TLogger : AcLoggerBase
        where TWriterBase : class, IAcLogWriterBase
    {
        services.AddSingleton<Func<string, TLogger>>(sp =>
        {
            var opts = sp.GetRequiredService<IOptions<AcLoggerOptions>>().Value;
            return categoryName =>
            {
                var writers = sp.GetServices<TWriterBase>().Cast<IAcLogWriterBase>().ToArray();
                return (TLogger)Activator.CreateInstance(typeof(TLogger), opts.AppType, opts.LogLevel, categoryName, writers)!;
            };
        });

        return services;
    }
}
