using ComputerShopContracts.BindingModels;
using ComputerShopContracts.ViewModels;
using ComputerShopDataModels.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ComputerShopDatabaseImplement.Models
{
	public class Request : IRequestModel
	{
		public int Id { get; private set; }
		[Required]
		public int UserId { get; private set; }

		public virtual User User { get; set; }

		public int? AssemblyId { get; set; }

		public virtual Assembly? Assembly { get; set; } = new();

		[Required]
		public DateTime DateRequest { get; set; }

		[Required]
		public string ClientFIO { get; set; } = string.Empty;

		private Dictionary<int, IOrderModel>? _requestOrders = null;

		[NotMapped]
		public Dictionary<int, IOrderModel> RequestOrders
		{
			get
			{
				if (_requestOrders == null)
				{
					_requestOrders = Orders.ToDictionary(x => x.OrderId, x => x.Order as IOrderModel);			

				}
				return _requestOrders;
			}
		}

		[ForeignKey("RequestId")]
		public virtual List<RequestOrder> Orders { get; set; } = new();


		public static Request Create(ComputerShopDatabase context, RequestBindingModel model)
		{
			return new Request() {
				Id = model.Id,
				UserId = model.UserId,
				User = context.Users.First(x => x.Id == model.UserId),
				AssemblyId = model.AssemblyId,
				Assembly = model.AssemblyId.HasValue ? context.Assemblies.First(x => x.Id == model.AssemblyId) : null,
				DateRequest = model.DateRequest,
				ClientFIO = model.ClientFIO,
				Orders = model.RequestOrders.Select(x => new RequestOrder
				{
					Order = context.Orders.First(y => y.Id == x.Key)
				}).ToList()
			};
		}

		public void Update(RequestBindingModel model)
		{
			if (model == null) { 
				return; 
			}
			if (!string.IsNullOrEmpty(model.ClientFIO))
			{
				ClientFIO = model.ClientFIO;
			}
			//DateMake не обновляю, потому что странно менять дату оформления заявки после её создания
			//Обновление ссылки на сборку (assemblyId) отдельным методом
		}

		public RequestViewModel GetViewModel => new()
		{
			Id = Id,
			UserId = UserId,
			AssemblyId = AssemblyId,
			Assembly = Assembly,
			DateRequest = DateRequest,
			ClientFIO = ClientFIO,
			RequestOrders = RequestOrders
		};

		//обновление списка заказов у заявки (+ изменение суммы у соответствующих заказов)
		public void UpdateOrders(ComputerShopDatabase context, RequestBindingModel model)
		{
			var currentRequest = context.Requests.First(x => x.Id == Id);
			//стоимость сборки, связанной с заявкой (или 0, если заявка не связана со сборкой)
			double price_of_assembly = (currentRequest.Assembly.Price != null) ? currentRequest.Assembly.Price : 0;
	
			var requestOrders = context.RequestOrders.Where(x => x.RequestId == model.Id).ToList();

			//удаление тех заказов, которых нет в модели (+ изменение суммы у удаляемых заказов)
			if (requestOrders != null && requestOrders.Count > 0)
			{
				var delOrders = requestOrders.Where(x => !model.RequestOrders.ContainsKey(x.OrderId));
				foreach (var delOrder in delOrders)
				{
					context.RequestOrders.Remove(delOrder);
					var order = context.Orders.First(x => x.Id == delOrder.OrderId);
					//вычитание из стоимости соответствующего заказа стоимость соответствующей сборки 
					order.ChangeSum(-price_of_assembly);
					context.SaveChanges();
				}
			}

			//добавление новых заказов (+ изменение суммы у добавляемых заказов)
			foreach (var request_order in model.RequestOrders)
			{
				var order = context.Orders.First(x => x.Id == request_order.Key);
				context.RequestOrders.Add(new RequestOrder
				{
					Request = currentRequest,
					Order = order
				});
				//увеличение стоимости заказа, с которым связываем заявку, на стоимость сборки
				order.ChangeSum(price_of_assembly);
				context.SaveChanges();
			}
			_requestOrders = null;
		}


		//Связывание заявки со сборкой (+ изменение суммы у соответствующих заказов)
		public void ConnectAssembly(ComputerShopDatabase context, RequestBindingModel model)
		{
			//стоимость старой сборки (или 0, если её не было)
			double price_of_old_assembly = (Assembly.Price != null) ? Assembly.Price : 0;

			AssemblyId = model.AssemblyId;
			Assembly = context.Assemblies.First(x => x.Id == model.AssemblyId);
			//изменение стоимости всех связанных заказов
			foreach (var request_order in model.RequestOrders)
			{
				var connectedOrder = context.Orders.First(x => x.Id == request_order.Key);
				//вычитание из стоимости заказа старой сборки
				connectedOrder.ChangeSum(-price_of_old_assembly);
				//прибавление стоимости новой сборки
				connectedOrder.ChangeSum(Assembly.Price);
				context.SaveChanges();
			}
		}
	}
}