using System;
using System.Collections.Generic;
using Autofac;

namespace eSuite.WorkBench.IoC
{
    public class IocContainer : IIocContainer
    {
        private IContainer _container;

        public event IocContainerRegisteringEventHandler Registering;

        private void BuildContainer()
        {
            List<IocRegistration> iocRegistrations = new List<IocRegistration>
            {
                new IocRegistration {Object = this, Type = typeof(IIocContainer), Singleton = true}
            };

            DoRegistering(iocRegistrations);

            var containerBuilder = new ContainerBuilder();

            foreach (IocRegistration iocRegistration in iocRegistrations)
            {
                if (iocRegistration.Singleton)
                {
                    if (iocRegistration.Object is Type type)
                    {
                        containerBuilder.RegisterType(type).As(iocRegistration.Type).SingleInstance();
                    }
                    else
                    {
                        containerBuilder.RegisterInstance(iocRegistration.Object).As(iocRegistration.Type).SingleInstance();
                    }
                }
                else
                {
                    if (iocRegistration.Object is Type type)
                    {
                        containerBuilder.RegisterType(type).As(iocRegistration.Type);
                    }
                    else
                    {
                        throw new ArgumentException("Cannot register instance for object as non singleton.");
                    }
                }
            }

            _container = containerBuilder.Build();
        }

        private void DoRegistering(List<IocRegistration> iocRegistrations)
        {
            if (Registering != null)
            {
                var args = new IocContainerRegisteringEventArgs
                {
                    IocRegistrations = iocRegistrations
                };

                Registering(this, args);
            }
        }

        public T Resolve<T>()
        {
            if (_container == null)
                BuildContainer();

            return _container.Resolve<T>();
        }

        public T Resolve<T>(IEnumerable<Parameter> parameters)
        {
            if (_container == null)
                BuildContainer();

            List<Autofac.Core.Parameter> parameterList = new List<Autofac.Core.Parameter>();

            foreach (var parameter in parameters)
            {
                if (parameter is TypedParameter typedParameter)
                {
                    parameterList.Add(AddTypedParameter(typedParameter));
                }
                else if (parameter is NamedParameter namedParameter)
                {
                    parameterList.Add(AddNamedParameter(namedParameter));
                }
            }

            return _container.Resolve<T>(parameterList);
        }

        private Autofac.Core.Parameter AddNamedParameter(NamedParameter parameter)
        {
            return new Autofac.NamedParameter(parameter.Name, parameter.Value);
        }

        private Autofac.Core.Parameter AddTypedParameter(TypedParameter parameter)
        {
            return new Autofac.TypedParameter(parameter.Type, parameter.Value);
        }
    }
}
