using EonaCat.LogStack.Configuration;
using EonaCat.LogStack.Core;
using EonaCat.LogStack.Logging;
using Microsoft.Extensions.DependencyInjection;
using System;

namespace EonaCat.LogStack.Extensions;

// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details.

/// <summary>
/// Extension methods for integrating EonaCat LogStack with Microsoft Dependency Injection
/// </summary>
public static class ServiceCollectionExtensions
{
    /// <summary>
    /// Registers EonaCat LogStack as the logging provider in the dependency injection container
    /// </summary>
    /// <param name="services">The service collection to register with</param>
    /// <param name="minimumLevel">The minimum log level to process</param>
    /// <param name="timestampMode">The timestamp mode to use</param>
    /// <returns>The service collection for chaining</returns>
    public static IServiceCollection AddEonaCatLogging(
        this IServiceCollection services,
        LogLevel minimumLevel = LogLevel.Trace,
        TimestampMode timestampMode = TimestampMode.Utc)
    {
        if (services == null)
        {
            throw new ArgumentNullException(nameof(services));
        }

        var loggerFactory = new LoggerFactory(minimumLevel, timestampMode);
        services.AddSingleton<ILoggerFactory>(loggerFactory);
        services.AddSingleton<Microsoft.Extensions.Logging.ILoggerFactory>(
            new MicrosoftExtensionsLoggerFactoryAdapter(loggerFactory));

        // Also register as ILogger for constructor injection
        services.AddSingleton(sp => sp.GetRequiredService<ILoggerFactory>().CreateLogger("Default"));
        services.AddSingleton(sp =>
            new MicrosoftExtensionsLoggerAdapter(
                sp.GetRequiredService<ILoggerFactory>().CreateLogger("Default")));

        return services;
    }

    /// <summary>
    /// Registers EonaCat LogStack using an existing EonaCatLogStack instance
    /// </summary>
    /// <param name="services">The service collection to register with</param>
    /// <param name="logStack">The pre-configured EonaCatLogStack instance</param>
    /// <returns>The service collection for chaining</returns>
    public static IServiceCollection AddEonaCatLogging(
        this IServiceCollection services,
        EonaCatLogStack logStack)
    {
        if (services == null)
        {
            throw new ArgumentNullException(nameof(services));
        }

        if (logStack == null)
        {
            throw new ArgumentNullException(nameof(logStack));
        }

        var loggerFactory = new LoggerFactory(logStack);
        services.AddSingleton<ILoggerFactory>(loggerFactory);
        services.AddSingleton<Microsoft.Extensions.Logging.ILoggerFactory>(
            new MicrosoftExtensionsLoggerFactoryAdapter(loggerFactory));

        // Also register as ILogger for constructor injection
        services.AddSingleton(sp => sp.GetRequiredService<ILoggerFactory>().CreateLogger("Default"));
        services.AddSingleton(sp =>
            new MicrosoftExtensionsLoggerAdapter(
                sp.GetRequiredService<ILoggerFactory>().CreateLogger("Default")));

        return services;
    }

    /// <summary>
    /// Registers EonaCat LogStack with a configuration callback
    /// </summary>
    /// <param name="services">The service collection to register with</param>
    /// <param name="configure">Callback to configure the EonaCatLogStack instance</param>
    /// <returns>The service collection for chaining</returns>
    public static IServiceCollection AddEonaCatLogging(
        this IServiceCollection services,
        Action<EonaCatLogStack> configure)
    {
        if (services == null)
        {
            throw new ArgumentNullException(nameof(services));
        }

        if (configure == null)
        {
            throw new ArgumentNullException(nameof(configure));
        }

        var logStack = new EonaCatLogStack();
        configure(logStack);

        var loggerFactory = new LoggerFactory(logStack);
        services.AddSingleton<ILoggerFactory>(loggerFactory);
        services.AddSingleton<Microsoft.Extensions.Logging.ILoggerFactory>(
            new MicrosoftExtensionsLoggerFactoryAdapter(loggerFactory));

        // Also register as ILogger for constructor injection
        services.AddSingleton(sp => sp.GetRequiredService<ILoggerFactory>().CreateLogger("Default"));
        services.AddSingleton(sp =>
            new MicrosoftExtensionsLoggerAdapter(
                sp.GetRequiredService<ILoggerFactory>().CreateLogger("Default")));

        return services;
    }

    /// <summary>
    /// Registers EonaCat LogStack using a fluent LogBuilder configuration.
    /// This is the recommended approach for DI integration with fluent configuration.
    /// </summary>
    /// <param name="services">The service collection to register with</param>
    /// <param name="category">The category/name of the logger</param>
    /// <param name="configure">Callback to configure the LogBuilder instance</param>
    /// <returns>The service collection for chaining</returns>
    public static IServiceCollection AddEonaCatLogging(
        this IServiceCollection services,
        string category,
        Action<LogBuilder> configure)
    {
        if (services == null)
        {
            throw new ArgumentNullException(nameof(services));
        }

        if (configure == null)
        {
            throw new ArgumentNullException(nameof(configure));
        }

        var builder = new LogBuilder(category);
        configure(builder);
        var logStack = builder.Build();

        var loggerFactory = new LoggerFactory(logStack);
        services.AddSingleton<ILoggerFactory>(loggerFactory);
        services.AddSingleton<Microsoft.Extensions.Logging.ILoggerFactory>(
            new MicrosoftExtensionsLoggerFactoryAdapter(loggerFactory));

        // Also register as ILogger for constructor injection
        services.AddSingleton(sp => sp.GetRequiredService<ILoggerFactory>().CreateLogger(category));
        services.AddSingleton(sp =>
            new MicrosoftExtensionsLoggerAdapter(
                sp.GetRequiredService<ILoggerFactory>().CreateLogger(category)));

        return services;
    }

    /// <summary>
    /// Registers EonaCat LogStack using a fluent LogBuilder configuration with "Application" as the default category.
    /// This is the recommended approach for DI integration with fluent configuration.
    /// </summary>
    /// <param name="services">The service collection to register with</param>
    /// <param name="configure">Callback to configure the LogBuilder instance</param>
    /// <returns>The service collection for chaining</returns>
    public static IServiceCollection AddEonaCatLogging(
        this IServiceCollection services,
        Action<LogBuilder> configure)
    {
        if (services == null)
        {
            throw new ArgumentNullException(nameof(services));
        }

        if (configure == null)
        {
            throw new ArgumentNullException(nameof(configure));
        }

        return services.AddEonaCatLogging("Application", configure);
    }

    /// <summary>
    /// Registers EonaCat LogStack as a factory using a LogBuilder configuration callback.
    /// Allows configuring the logger factory through DI with full access to the service provider.
    /// </summary>
    /// <param name="services">The service collection to register with</param>
    /// <param name="category">The category/name of the logger</param>
    /// <param name="configure">Callback to configure the LogBuilder instance</param>
    /// <returns>The service collection for chaining</returns>
    public static IServiceCollection AddEonaCatLoggingFactory(
        this IServiceCollection services,
        string category,
        Action<LogBuilder> configure)
    {
        if (services == null)
        {
            throw new ArgumentNullException(nameof(services));
        }

        if (configure == null)
        {
            throw new ArgumentNullException(nameof(configure));
        }

        services.AddSingleton<ILoggerFactory>(sp =>
        {
            var builder = new LogBuilder(category);
            configure(builder);
            var logStack = builder.Build();
            return new LoggerFactory(logStack);
        });

        services.AddSingleton<Microsoft.Extensions.Logging.ILoggerFactory>(sp =>
            new MicrosoftExtensionsLoggerFactoryAdapter(
                sp.GetRequiredService<ILoggerFactory>()));

        // Also register as ILogger for constructor injection
        services.AddSingleton(sp => sp.GetRequiredService<ILoggerFactory>().CreateLogger(category));
        services.AddSingleton(sp =>
            new MicrosoftExtensionsLoggerAdapter(
                sp.GetRequiredService<ILoggerFactory>().CreateLogger(category)));

        return services;
    }

    /// <summary>
    /// Registers EonaCat LogStack as a factory using a LogBuilder configuration callback with "Application" as default category.
    /// Allows configuring the logger factory through DI with full access to the service provider.
    /// </summary>
    /// <param name="services">The service collection to register with</param>
    /// <param name="configure">Callback to configure the LogBuilder instance</param>
    /// <returns>The service collection for chaining</returns>
    public static IServiceCollection AddEonaCatLoggingFactory(
        this IServiceCollection services,
        Action<LogBuilder> configure)
    {
        if (services == null)
        {
            throw new ArgumentNullException(nameof(services));
        }

        if (configure == null)
        {
            throw new ArgumentNullException(nameof(configure));
        }

        return services.AddEonaCatLoggingFactory("Application", configure);
    }

    /// <summary>
    /// Registers EonaCat LogStack with AdvancedLoggerFactory for enhanced features like category-specific configuration and context propagation
    /// </summary>
    /// <param name="services">The service collection to register with</param>
    /// <param name="minimumLevel">The minimum log level to process</param>
    /// <param name="timestampMode">The timestamp mode to use</param>
    /// <returns>The service collection for chaining</returns>
    public static IServiceCollection AddAdvancedEonaCatLogging(
        this IServiceCollection services,
        LogLevel minimumLevel = LogLevel.Trace,
        TimestampMode timestampMode = TimestampMode.Utc)
    {
        if (services == null)
        {
            throw new ArgumentNullException(nameof(services));
        }

        var advancedFactory = new AdvancedLoggerFactory(minimumLevel, timestampMode);
        services.AddSingleton(advancedFactory);
        services.AddSingleton<ILoggerFactory>(advancedFactory);
        services.AddSingleton<Microsoft.Extensions.Logging.ILoggerFactory>(
            new MicrosoftExtensionsLoggerFactoryAdapter(advancedFactory));

        // Also register as ILogger for constructor injection
        services.AddSingleton(sp => sp.GetRequiredService<AdvancedLoggerFactory>().CreateLogger("Default"));
        services.AddSingleton(sp =>
            new MicrosoftExtensionsLoggerAdapter(
                sp.GetRequiredService<AdvancedLoggerFactory>().CreateLogger("Default")));

        return services;
    }

    /// <summary>
    /// Registers EonaCat LogStack with AdvancedLoggerFactory and a configuration callback
    /// </summary>
    /// <param name="services">The service collection to register with</param>
    /// <param name="configure">Callback to configure the AdvancedLoggerFactory</param>
    /// <returns>The service collection for chaining</returns>
    public static IServiceCollection AddAdvancedEonaCatLogging(
        this IServiceCollection services,
        Action<AdvancedLoggerFactory> configure)
    {
        if (services == null)
        {
            throw new ArgumentNullException(nameof(services));
        }

        if (configure == null)
        {
            throw new ArgumentNullException(nameof(configure));
        }

        services.AddSingleton<AdvancedLoggerFactory>(sp =>
        {
            var factory = new AdvancedLoggerFactory();
            configure(factory);
            return factory;
        });

        services.AddSingleton<ILoggerFactory>(sp => sp.GetRequiredService<AdvancedLoggerFactory>());
        services.AddSingleton<Microsoft.Extensions.Logging.ILoggerFactory>(sp =>
            new MicrosoftExtensionsLoggerFactoryAdapter(sp.GetRequiredService<AdvancedLoggerFactory>()));

        // Also register as ILogger for constructor injection
        services.AddSingleton(sp => sp.GetRequiredService<AdvancedLoggerFactory>().CreateLogger("Default"));
        services.AddSingleton(sp =>
            new MicrosoftExtensionsLoggerAdapter(
                sp.GetRequiredService<AdvancedLoggerFactory>().CreateLogger("Default")));

        return services;
    }

    /// <summary>
    /// Registers the AdvancedMetricsCollector for system-wide analytics
    /// </summary>
    /// <param name="services">The service collection to register with</param>
    /// <returns>The service collection for chaining</returns>
    public static IServiceCollection AddEonaCatMetricsCollection(
        this IServiceCollection services)
    {
        if (services == null)
        {
            throw new ArgumentNullException(nameof(services));
        }

        services.AddSingleton<AdvancedMetricsCollector>();
        return services;
    }
}
