using System.Reflection;
using DiunaBI.Infrastructure.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; 

namespace DiunaBI.Infrastructure.Services;

public class PluginManager
{
    private readonly ILogger<PluginManager> _logger;
    private readonly IServiceProvider _serviceProvider;
    private readonly List<Type> _processorTypes = new();
    private readonly List<Type> _importerTypes = new();
    private readonly List<IDataExporter> _exporters = new();
    private readonly List<IPlugin> _plugins = new();

    public PluginManager(ILogger<PluginManager> logger, IServiceProvider serviceProvider)
    {
        _logger = logger;
        _serviceProvider = serviceProvider;
    }

    public void LoadPluginsFromDirectory(string pluginsPath)
    {
        if (!Directory.Exists(pluginsPath))
        {
            _logger.LogWarning("Plugins directory not found: {Path}", pluginsPath);
            return;
        }

        var dllFiles = Directory.GetFiles(pluginsPath, "*.dll", SearchOption.AllDirectories);

        foreach (var dllFile in dllFiles)
        {
            try
            {
                LoadPluginFromAssembly(dllFile);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to load plugin from {File}", dllFile);
            }
        }

        _logger.LogInformation("Loaded {ProcessorCount} processors and {ImporterCount} importers from {AssemblyCount} assemblies",
            _processorTypes.Count,
            _importerTypes.Count,
            dllFiles.Length);  // Zmień z _plugins.Count na assemblyFiles.Length
    }

    private void LoadPluginFromAssembly(string assemblyPath)
    {
        _logger.LogDebug("Loading assembly from: {Path}", assemblyPath); // Information -> Debug

        try
        {
            var assembly = Assembly.LoadFrom(assemblyPath);
            _logger.LogDebug("Assembly loaded successfully: {Name}", assembly.FullName); // Information -> Debug

            foreach (var type in assembly.GetTypes())
            {
                if (typeof(IDataProcessor).IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract)
                {
                    _processorTypes.Add(type);
                    _logger.LogDebug("Registered processor: {Type}", type.Name); // Information -> Debug
                }

                if (typeof(IDataImporter).IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract)
                {
                    _importerTypes.Add(type);
                    _logger.LogDebug("Registered importer: {Type}", type.Name); // Information -> Debug
                }
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to load assembly from {Path}", assemblyPath); // ZOSTAW jako Error
        }
    }

    public IDataProcessor? GetProcessor(string processorType)
    {
        foreach (var type in _processorTypes)
        {
            try
            {
                using var scope = _serviceProvider.CreateScope();
                var instance = (IDataProcessor)ActivatorUtilities.CreateInstance(scope.ServiceProvider, type);

                if (instance.CanProcess(processorType))
                {
                    var scopedProvider = _serviceProvider.CreateScope().ServiceProvider;
                    return (IDataProcessor)ActivatorUtilities.CreateInstance(scopedProvider, type);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to create processor instance of type {Type}", type.Name);
            }
        }
        return null;
    }

    public IDataImporter? GetImporter(string importerType)
    {
        foreach (var type in _importerTypes)
        {
            try
            {
                using var scope = _serviceProvider.CreateScope();
                var instance = (IDataImporter)ActivatorUtilities.CreateInstance(scope.ServiceProvider, type);

                if (instance.CanImport(importerType))
                {
                    var scopedProvider = _serviceProvider.CreateScope().ServiceProvider;
                    return (IDataImporter)ActivatorUtilities.CreateInstance(scopedProvider, type);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to create importer instance of type {Type}", type.Name);
            }
        }
        return null;
    }

    public IDataExporter? GetExporter(string exporterType)
    {
        return _exporters.FirstOrDefault(e => e.CanExport(exporterType));
    }
    public int GetPluginsCount() => _processorTypes.Count + _importerTypes.Count + _exporters.Count;
}