using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Core;
using VIZ.Package.Domain;
using VIZ.Package.Plugin;

namespace VIZ.Package.Service
{
    /// <summary>
    /// 插件服务
    /// </summary>
    public class PluginService
    {
        /// <summary>
        /// 日志
        /// </summary>
        private static ILog log = LogManager.GetLogger(typeof(PluginService));

        /// <summary>
        /// 包装插件前缀
        /// </summary>
        public const string PLUGIN_ASSEMBLY_PREFIX = "VIZ.";

        /// <summary>
        /// 加载插件信息集合
        /// </summary>
        /// <returns>插件信息集合</returns>
        public List<PluginInfo> LoadPluginInfos()
        {
            List<PluginInfo> list = new List<PluginInfo>();

            ApplicationDllCheckAttribute entry_attribute = Assembly.GetEntryAssembly().GetCustomAttribute<ApplicationDllCheckAttribute>();
            if (entry_attribute == null || string.IsNullOrWhiteSpace(entry_attribute.Key))
                return list;

            string[] files = System.IO.Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory);

            Type pluginLifeCycleType = typeof(IPluginLifeCycle);

            foreach (string file in files)
            {
                string fileName = System.IO.Path.GetFileName(file);

                if (!fileName.StartsWith(PLUGIN_ASSEMBLY_PREFIX) || !fileName.EndsWith(".dll"))
                    continue;

                Assembly assembly = Assembly.LoadFile(file);

                string version = assembly.GetCustomAttribute<AssemblyVersionAttribute>()?.Version;
                Type[] types = assembly.GetTypes();

                foreach (Type type in types)
                {
                    if (!type.IsClass)
                        continue;

                    if (!pluginLifeCycleType.IsAssignableFrom(type))
                        continue;

                    IPluginLifeCycle lifeCycle = type.Assembly.CreateInstance(type.FullName) as IPluginLifeCycle;
                    if (lifeCycle == null)
                    {
                        log.Error($"init plugin type: {type.FullName} error.");
                        continue;
                    }

                    ApplicationDllCheckAttribute attribute = type.Assembly.GetCustomAttribute<ApplicationDllCheckAttribute>();
                    if (attribute == null)
                        continue;

                    if (!string.Equals(entry_attribute.Key, attribute.Key))
                        continue;

                    PluginInfo info = null;
                    try
                    {
                        info = lifeCycle.Register();
                    }
                    catch (Exception ex)
                    {
                        log.Error(ex);

                        break;
                    }
                    list.Add(info);
                }
            }

            return list;
        }
    }
}
