using ModuleTools.Attributes;
using System;
using System.Reflection;

namespace ModuleTools.BusinessLogics
{
	/// <summary>
	/// Маппер сущностей
	/// </summary>
	public class Mapper
	{
		/// <summary>
		/// Преобразование из одного класса в другой
		/// </summary>
		/// <typeparam name="From"></typeparam>
		/// <typeparam name="To"></typeparam>
		/// <param name="obj"></param>
		/// <param name="haveRigth"></param>
		/// <returns></returns>
		public static To MapToClass<From, To>(From obj, bool haveRigth) where To : class => FillObject(obj, (To)Activator.CreateInstance(typeof(To)), haveRigth);

		/// <summary>
		/// Преобразование из одного класса в другой
		/// </summary>
		/// <typeparam name="From"></typeparam>
		/// <typeparam name="To"></typeparam>
		/// <param name="obj"></param>
		/// <param name="newObject"></param>
		/// <returns></returns>
		public static To MapToClass<From, To>(From obj, To newObject, bool haveRigth) where To : class => FillObject(obj, newObject, haveRigth);

		/// <summary>
		/// Заполнение объекта
		/// </summary>
		/// <typeparam name="From"></typeparam>
		/// <typeparam name="To"></typeparam>
		/// <param name="obj"></param>
		/// <param name="newObject"></param>
		/// <param name="haveRigth"></param>
		/// <returns></returns>
		private static To FillObject<From, To>(From obj, To newObject, bool haveRigth)
			where To : class
		{
			if (obj == null)
			{
				return null;
			}

			if (newObject == null)
			{
				return null;
			}
			var typeFrom = typeof(From);
			var typeTo = typeof(To);
			var properties = typeTo.GetProperties();
			foreach (var property in properties)
			{
				var customAttribute = property.GetCustomAttribute<MapConfigurationAttribute>();
				if (customAttribute != null)
				{
					object value = obj;
					if (customAttribute.IsDifficle)
					{
						var props = customAttribute.PropertyNameFromModel.Split('.');
						foreach (var prop in props)
						{
							var bindingProperty = value.GetType().GetProperty(prop);
							if (bindingProperty != null)
							{
								value = bindingProperty.GetValue(value);
								if (value is null)
								{
									break;
								}
							}
							else
							{
								value = null;
								break;
							}
						}
					}
					else
					{
						var bindingProperty = typeFrom.GetProperty(customAttribute.PropertyNameFromModel);
						if (bindingProperty != null)
						{
							value = bindingProperty.GetValue(obj);
						}
					}
					if (value is null)
					{
						continue;
					}
					if ((haveRigth && !customAttribute.AllowCopyWithoutRigth) || customAttribute.AllowCopyWithoutRigth)
					{
						property.SetValue(newObject, value);
					}
				}
			}

			return newObject;
		}
	}
}