using System;
using System.Linq;
using Unity;
using Unity.Interception;
using Unity.Interception.ContainerIntegration;
using Unity.Interception.Interceptors.InstanceInterceptors.InterfaceInterception;
using Unity.Lifetime;
using VCommon.Reflection;

namespace VCommon.Ioc
{
    public class IocManager : IIocManager
    {
        public IUnityContainer Container { get; }

        public IocManager()
        {
            Container = new UnityContainer();

            Container.AddNewExtension<Interception>();

            var allTypes = TypeFinder.AllTypes;
            foreach (var type in allTypes) RegisterType(type);

            RegisterInstanceToContainer<IIocManager>(this);
        }

        private IocManager(IUnityContainer container)
        {
            Container = container;
        }

        private void RegisterType(Type type)
        {
            var interfaces = type.FilterInterfaces(
                new[]
                {
                    typeof(ISingletonIocClass),
                    typeof(ISingletonIocClass<>),
                    typeof(ITransientIocClass),
                    typeof(ITransientIocClass<>)
                }
                , out var remainInterfaces
            );

            if (interfaces.Count == 0) return;

            if (interfaces.Count > 1) throw new VIocException($"Ioc接口只能有一个: {type.FullName}");
            var keyValuePair = interfaces.First();
            var list = keyValuePair.Value;
            if (list.Length != 1) throw new VIocException($"Ioc接口只能有一个: {type.FullName}");

            var iocDefine = keyValuePair.Key;
            var iocInterface = list[0];

            if (iocDefine == typeof(ITransientIocClass<>))
            {
                var interceptorClassTarget = iocInterface.GetGenericArguments()[0];

                var interceptorClass = typeof(InterceptionBehaviorAdapter<>).MakeGenericType(interceptorClassTarget);

                foreach (var ri in remainInterfaces)
                {
                    Container.RegisterType(ri, type, new TransientLifetimeManager()
                        , new Interceptor<InterfaceInterceptor>()
                        , new InterceptionBehavior(interceptorClass));
                }
            }
            else if (iocDefine == typeof(ISingletonIocClass<>))
            {
                var interceptorClassTarget = iocInterface.GetGenericArguments()[0];

                var interceptorClass = typeof(InterceptionBehaviorAdapter<>).MakeGenericType(interceptorClassTarget);

                foreach (var ri in remainInterfaces)
                {
                    Container.RegisterType(ri, type, new ContainerControlledLifetimeManager()
                        , new Interceptor<InterfaceInterceptor>()
                        , new InterceptionBehavior(interceptorClass));
                }
            }
            else if (iocDefine == typeof(ITransientIocClass))
            {
                Container.RegisterType(type, type, new TransientLifetimeManager());
                foreach (var ri in remainInterfaces) Container.RegisterType(ri, type, new TransientLifetimeManager());
            }
            else if (iocDefine == typeof(ISingletonIocClass))
            {
                Container.RegisterType(type, type, new ContainerControlledLifetimeManager());
                foreach (var ri in remainInterfaces) Container.RegisterType(ri, type, new ContainerControlledLifetimeManager());
            }
            else
            {
                throw new VIocException($"这是什么Ioc接口? {iocDefine.FullName}");
            }
        }

        public bool IsRegistered(Type type) => Container.IsRegistered(type);

        public object Resolve(Type type) => Container.Resolve(type, null);

        public T Resolve<T>() => Container.Resolve<T>();

        public bool IsRegistered<T>() => Container.IsRegistered<T>();

        /// <summary> 手动注册用以覆盖自动注册 </summary>
        public void RegisterManually<T>() => RegisterType(typeof(T));

        /// <summary> 将单例实例注册到容器中,使用相同的类型注入 </summary>
        public void RegisterInstanceToContainer<T>(T instance) => Container.RegisterInstance<T>(instance, new ContainerControlledLifetimeManager());

        public IIocManager CreateChildren()
        {
            var children = new IocManager(Container.CreateChildContainer());
            children.RegisterInstanceToContainer<IIocManager>(children);
            return children;
        }

        public void Dispose() => Container?.Dispose();
    }

    //TOD: Child Container

    public interface IIocManager:IDisposable
    {
        bool IsRegistered(Type type);

        bool IsRegistered<T>();

        T Resolve<T>();

        object Resolve(Type type);

        bool TryResolve<T>(out T instance)
        {
            if (IsRegistered<T>())
            {
                instance = Resolve<T>();
                return true;
            }
            instance = default(T);
            return false;
        }

        void RegisterManually<T>();

        void RegisterInstanceToContainer<T>(T instance);


        IIocManager CreateChildren();
    }
}
