using Inspectron.Settings;
using Ninject;
using Ninject.Extensions.ChildKernel;
using Serilog;
using System.ComponentModel;
using VisionBuilder.UI.Common.Attributes;
using VisionBuilder.UI.Common.Plugins;

namespace VisionBuilder.UI.Common;

public static class Extensions
{
    public static void RegisterSettings(this IKernel self)
    {
        // get all types from kernel that implement ISettings
        var settingsTypes = self.GetAll(typeof(ISettings)).Select(x=>(ISettings)x).ToList();
        // register each type as ISettings
        foreach (var settingsInstance in settingsTypes)
        {
            settingsInstance.RegisterSettings(self.Get<InspectronSettings>());
        }
    }

    public static void RegisterModule<T>(this IKernel self) where T : IVisionBuilderModule
    {
        self.Bind<T, IVisionBuilderModule>().To<T>().InSingletonScope();
    }


    private static int GetModulePriority(IVisionBuilderModule module)
    {
        var priorityAttribute = module.GetType().GetCustomAttributes(typeof(ModulePriorityAttribute), true)
            .FirstOrDefault() as ModulePriorityAttribute;
        return priorityAttribute?.Priority ?? 0;
    }

    static Dictionary<IKernel,List<Type>> _initializedModules = new Dictionary<IKernel, List<Type>>();
    

    public static void InitializeModules(this IKernel self)
    {
        if (!_initializedModules.ContainsKey(self)) _initializedModules[self] = new List<Type>();

        var serviceTypes = self.GetAll(typeof(IVisionBuilderModule)).Select(x => (IVisionBuilderModule)x)
            .Where(x => !_initializedModules[self].Contains(x.GetType()))
            .OrderByDescending(GetModulePriority)
            .ToList();
        foreach (var service in serviceTypes)
        {
            try
            {
                if (service != null)
                {
                    Log.Information($"Initializing module {service.GetType().Name}");
                    service.InitializeModule();
                }
            }
            catch (Exception e)
            {
                Log.Error($"Error initializing module {service.GetType().Name}: {e}", e);   
            }
            
            _initializedModules[self].Add(service.GetType());
        }
    }

    public static IKernel UsePlugins(this IKernel self, string pluginsProfile)
    {
        self.RegisterModule<PluginLoader>();
        self.Get<PluginLoader>().InitializeModule(pluginsProfile);
        return self;
    }


    public static IKernel RegisterGlobalPlugins(this IKernel self)
    {
        var plugins = self.Get<PluginLoader>().Plugins;
        foreach (var plugin in plugins)
        {
            try
            {
                Log.Information($"Initializing global plugin {plugin.GetType().Name}");
                plugin.RegisterGlobalModules(self);
            }
            catch (Exception e)
            {
                Log.Error($"Error initializing global plugin {plugin.GetType().Name}: {e}", e);
            }
        }
        return self;
    }

    public static IKernel RegisterCameraPlugins(this IChildKernel self, string cameraName)
    {
        var plugins = self.Get<PluginLoader>().Plugins;
        foreach (var plugin in plugins)
        {
            try
            {
                Log.Information($"Initializing camera plugin {plugin.GetType().Name} for camera {cameraName}");
                plugin.RegisterCameraModules(self,cameraName);
            }
            catch (Exception e)
            {
                Log.Error($"Error initializing camera plugin {plugin.GetType().Name} for camera {cameraName}: {e}", e);
            }
        }
        return self;
    }






}