using FlowerShopContracts.BindingModels;
using FlowerShopContracts.BusinessLogicsContracts;
using FlowerShopContracts.SearchModels;
using FlowerShopContracts.StoragesContracts;
using FlowerShopContracts.ViewModels;
using Microsoft.Extensions.Logging;

namespace FlowerShopBusinessLogic.BusinessLogics
{
	public class ImplementerLogic : IImplementerLogic
	{
		private readonly ILogger _logger;
		private readonly IImplementerStorage _implementerStorage;
		public ImplementerLogic(ILogger<IImplementerLogic> Logger, IImplementerStorage ImplementerStorage)
		{
			_logger = Logger;
			_implementerStorage = ImplementerStorage;
		}
		public List<ImplementerViewModel>? ReadList(ImplementerSearchModel? Model)
		{
			_logger.LogInformation("ReadList. ImplementerFIO: {ImplementerFIO}. Password: {Password}. Id: {Id}",
				Model?.ImplementerFIO, Model?.Password?.Length, Model?.Id);

			var List = Model == null ? _implementerStorage.GetFullList() : _implementerStorage.GetFilteredList(Model);

			if (List == null)
			{
				_logger.LogWarning("ReadList return null list");
				return null;
			}

			_logger.LogInformation("ReadList. Count: {Count}", List.Count);
			return List;
		}
		public ImplementerViewModel? ReadElement(ImplementerSearchModel Model)
		{
			if (Model is null)
			{
				throw new ArgumentNullException(nameof(Model));
			}

			_logger.LogInformation("ReadElement. ImplementerFIO: {ImplementerFIO}. Password: {Password}. Id: {Id}",
				Model?.ImplementerFIO, Model?.Password?.Length, Model?.Id);

			var Element = _implementerStorage.GetElement(Model);

			if (Element == null)
			{
				_logger.LogWarning("ReadElement element not found");
				return null;
			}

			_logger.LogInformation("ReadElement find. Id: {Id}", Element.Id);
			return Element;
		}
		public bool Create(ImplementerBindingModel Model)
		{
			CheckModel(Model);

			if (_implementerStorage.Insert(Model) == null)
			{
				_logger.LogWarning("Insert operation failed");
				return false;
			}

			return true;
		}
		public bool Update(ImplementerBindingModel Model)
		{
			CheckModel(Model);

			if (_implementerStorage.Update(Model) == null)
			{
				_logger.LogWarning("Update operation failed");
				return false;
			}

			return true;
		}
		public bool Delete(ImplementerBindingModel Model)
		{
			CheckModel(Model, false);

			_logger.LogInformation("Delete. Id:{Id}", Model.Id);

			if (_implementerStorage.Delete(Model) == null)
			{
				_logger.LogWarning("Delete operation failed");
				return false;
			}

			return true;
		}
		private void CheckModel(ImplementerBindingModel Model, bool WithParams = true)
		{
			if (Model == null)
				throw new ArgumentNullException(nameof(Model));

			if (!WithParams)
				return;

			if (string.IsNullOrEmpty(Model.ImplementerFIO))
				throw new ArgumentNullException("Нет ФИО исполнителя", nameof(Model.ImplementerFIO));

			if (string.IsNullOrEmpty(Model.Password))
				throw new ArgumentNullException("Нет пароля исполнителя", nameof(Model.Password));

			if (Model.WorkExperience < 0)
				throw new ArgumentNullException("Стаж должен быть неотрицательным целым числом", nameof(Model.WorkExperience));

			if (Model.Qualification < 0)
				throw new ArgumentNullException("Квалификация должна быть неотрицательным целым числом", nameof(Model.Qualification));

			_logger.LogInformation("Implementer. ImplementerFIO: {ImplementerFIO}. Password: {Password}. WorkExperience: {WorkExperience}. Qualification: {Qualification}. Id: {Id}",
				Model.ImplementerFIO, Model.Password, Model.WorkExperience, Model.Qualification, Model.Id);

			var Implementer = _implementerStorage.GetElement(new ImplementerSearchModel
			{
				ImplementerFIO = Model.ImplementerFIO
			});

			if (Implementer != null && Implementer.Id != Model.Id)
			{
				throw new InvalidOperationException("Исполнитель с таким ФИО уже есть");
			}
		}
	}
}