using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DiplomovaPrace.Contracts;
using DiplomovaPrace.Contracts.Orders;
using DiplomovaPrace.Contracts.Orders.InputModels;
using DiplomovaPrace.Contracts.Orders.ViewModels;
using DiplomovaPrace.Web.Admin.Store.DeliveryTypeUseCase.Actions;
using DiplomovaPrace.Web.Admin.Store.OrderStateUseCase.Actions;
using DiplomovaPrace.Web.Admin.Store.PaymentStateUseCase.Actions;
using DiplomovaPrace.Web.Admin.Store.PaymentTypeUseCase.Actions;
using Fluxor;

namespace DiplomovaPrace.Web.Admin.Services
{
	public class OrderService : IOrderService
	{
		private readonly IDispatcher dispatcher;
		private readonly IDeliveryTypeFacadeContract deliveryTypeFacadeContract;
		private readonly IOrderFacadeContract orderFacadeContract;
		private readonly IOrderStateFacadeContract orderStateFacadeContract;
		private readonly IPaymentStateFacadeContract paymentStateFacadeContract;
		private readonly IPaymentTypeFacadeContract paymentTypeFacadeContract;

		public OrderService(IDispatcher dispatcher,
			IDeliveryTypeFacadeContract deliveryTypeFacadeContract,
			IOrderFacadeContract orderFacadeContract,
			IOrderStateFacadeContract orderStateFacadeContract,
			IPaymentStateFacadeContract paymentStateFacadeContract,
			IPaymentTypeFacadeContract paymentTypeFacadeContract)
		{
			this.dispatcher = dispatcher;
			this.deliveryTypeFacadeContract = deliveryTypeFacadeContract;
			this.orderFacadeContract = orderFacadeContract;
			this.orderStateFacadeContract = orderStateFacadeContract;
			this.paymentStateFacadeContract = paymentStateFacadeContract;
			this.paymentTypeFacadeContract = paymentTypeFacadeContract;
		}

		public async Task RequestOrderPropertiesAsync()
		{
			List<DeliveryTypeVM> deliveryTypes = await deliveryTypeFacadeContract.GetAllDeliveryTypesAsync().ConfigureAwait(false);
			List<OrderStateVM> orderStates = await orderStateFacadeContract.GetAllOrderStatesAsync().ConfigureAwait(false);
			List<PaymentStateVM> paymentStates = await paymentStateFacadeContract.GetAllPaymentStatesAsync().ConfigureAwait(false);
			List<PaymentTypeVM> paymentTypes = await paymentTypeFacadeContract.GetAllPaymentTypesAsync().ConfigureAwait(false);

			dispatcher.Dispatch(new ReceiveDeliveryTypesAction(deliveryTypes));
			dispatcher.Dispatch(new ReceiveOrderStatesAction(orderStates));
			dispatcher.Dispatch(new ReceivePaymentStatesAction(paymentStates));
			dispatcher.Dispatch(new ReceivePaymentTypesAction(paymentTypes));
		}

		public async Task<OrderIM> GetOrderByIDAsync(ValueDto<int> orderID)
		{
			OrderDetailVM order = await orderFacadeContract.GetOrderDetailByIDAsync(orderID).ConfigureAwait(false);

			return new OrderIM
			{
				DeliveryAddress = order.DeliveryAddress is null
				? null
				: new()
				{
					FirstName = order.DeliveryAddress.FirstName,
					LastName = order.DeliveryAddress.LastName,
					PhoneNumber = order.DeliveryAddress.PhoneNumber,
					City = order.DeliveryAddress.City,
					Street = order.DeliveryAddress.Street,
					ZipCode = order.DeliveryAddress.ZipCode,
					State = order.DeliveryAddress.State
				},
				InvoicingAddress = new()
				{
					FirstName = order.InvoicingAddress.FirstName,
					LastName = order.InvoicingAddress.LastName,
					PhoneNumber = order.InvoicingAddress.PhoneNumber,
					City = order.InvoicingAddress.City,
					Street = order.InvoicingAddress.Street,
					ZipCode = order.InvoicingAddress.ZipCode,
					State = order.InvoicingAddress.State
				},
				LoginAccount = new()
				{
					FirstName = order.LoginAccount.FirstName,
					LastName = order.LoginAccount.LastName,
					Email = order.LoginAccount.Email
				},
				DeliveryTypeID = (int)order.DeliveryTypeID,
				OrderStateID = order.OrderStateID,
				PaymentStateID = (int)order.PaymentStateID,
				PaymentTypeID = (int)order.PaymentTypeID,
				OrderItems = order.OrderItems.Select(i =>
				new OrderItemIM
				{
					ID = i.ID,
					ProductID = i.ProductID,
					Name = i.Name,
					Price = i.Price,
					Amount = i.Amount,
					TotalPrice = i.TotalPrice
				}).ToList(),
				TotalPrice = order.TotalPrice,
				OrderedDate = order.OrderedDate.Value
			};
		}

		public async Task<bool> DeleteOrder(ValueDto<int> orderId)
		{
			ValueDto<bool> result = await orderFacadeContract.DeleteOrderAsync(orderId).ConfigureAwait(false);

			return result.Value;
		}
	}
}
