using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Blazored.Modal;
using Blazored.Modal.Services;
using Blazored.Toast.Services;
using DiplomovaPrace.Contracts;
using DiplomovaPrace.Contracts.Addresses;
using DiplomovaPrace.Contracts.Orders;
using DiplomovaPrace.Contracts.Orders.InputModels;
using DiplomovaPrace.Web.Admin.Pages.Orders.Modal;
using DiplomovaPrace.Web.Admin.Services;
using DiplomovaPrace.Web.Admin.Shared.Common;
using DiplomovaPrace.Web.Admin.Store.DeliveryTypeUseCase;
using DiplomovaPrace.Web.Admin.Store.OrderStateUseCase;
using DiplomovaPrace.Web.Admin.Store.PaymentStateUseCase;
using DiplomovaPrace.Web.Admin.Store.PaymentTypeUseCase;
using Fluxor;
using Microsoft.AspNetCore.Components;

namespace DiplomovaPrace.Web.Admin.Pages.Orders
{
	public partial class UpdateOrder
	{
		[Parameter]
		public int OrderID { get; set; }

		[CascadingParameter]
		public IModalService Modal { get; set; }

		[Inject]
		private IAddressFacadeContract AddressFacadeContract { get; set; }

		[Inject]
		private IOrderFacadeContract OrderFacadeContract { get; set; }

		[Inject]
		private IOrderService OrderService { get; set; }

		[Inject]
		private IState<DeliveryTypeState> DeliveryTypeState { get; set; }

		[Inject]
		private IState<OrderState> OrderState { get; set; }

		[Inject]
		private IState<PaymentState> PaymentState { get; set; }

		[Inject]
		private IState<PaymentTypeState> PaymentTypeState { get; set; }

		[Inject]
		private IToastService ToastService { get; set; }

		private List<AddressDto> invoicingAddresses = new();

		private List<AddressDto> deliveryAddresses = new();

		private OrderIM order;

		private decimal? serviceFee;

		protected override async Task OnInitializedAsync()
		{
			await base.OnInitializedAsync().ConfigureAwait(false);

			await LoadAllOrderPropertiesAsync().ConfigureAwait(false);
			order = await OrderFacadeContract.GetOrderToUpdateByIDAsync(ValueDto.FromValue(OrderID)).ConfigureAwait(false);
			if ( order.LoginAccount is not null)
			{
				deliveryAddresses = await AddressFacadeContract.GetDeliveryAddressesByUserAsync(ValueDto.FromValue(order.LoginAccount.Email)).ConfigureAwait(false);
				invoicingAddresses = await AddressFacadeContract.GetInvoicingAddressesByUserAsync(ValueDto.FromValue(order.LoginAccount.Email)).ConfigureAwait(false);
			}
			else
			{
				// vzdy musi vratit fakturacni adresu (jen jednu!), protoze nemuze existovat objednavka bez fakturacni adresy
				invoicingAddresses.Add(await AddressFacadeContract.GetInvoicingAddressesByIDAsync(ValueDto.FromValue(order.InvoicingAddressID)));

				AddressDto deliveryAddress = order.DeliveryAddressID > 0
				? await AddressFacadeContract.GetDeliveryAddressesByIDAsync(ValueDto.FromValue(order.DeliveryAddressID))
				: null;

				if (deliveryAddress is not null)
				{
					deliveryAddresses.Add(deliveryAddress);
					order.DeliveryAddress = deliveryAddress; // kvuli moznemu odstraneni adresy
				}
			}
		}

		private async Task LoadAllOrderPropertiesAsync()
		{
			if (DeliveryTypeState.Value.DeliveryTypes is null ||
				OrderState.Value.OrderStates is null ||
				PaymentState.Value.PaymentStates is null ||
				PaymentTypeState.Value.PaymentTypes is null)
			{
				await OrderService.RequestOrderPropertiesAsync().ConfigureAwait(false);
			}
		}

		private async Task HandleRemoveOrderItemButtonClick(OrderItemIM item)
		{
			ModalOptions options = new()
			{
				DisableBackgroundCancel = true,
				Animation = ModalAnimation.FadeInOut(0.25),
				HideCloseButton = true
			};
			ModalParameters parameters = new();

			parameters.Add("ConfirmButtonText", "Odebrat");
			parameters.Add("CancelButtonText", "Zrušit");
			parameters.Add("BodyText", $"Opravdu chcete odebrat produkt: <b>{item.Name}</b>?");

			ModalResult result = await Modal.Show<ConfirmModal>("Odebrání produktu", parameters, options).Result.ConfigureAwait(false);

			if (result.Cancelled)
			{
				return;
			}

			order.OrderItems.Remove(item);
		}

		private async Task HandleInvoicingAddressChangeAsync(ChangeEventArgs e)
		{
			if (int.TryParse(e.Value.ToString(), out int addressID))
			{
				if (addressID == 0)
				{
					order.InvoicingAddressID = -1;
					await ShowAddressCreateModalAsync((int)AddressType.InvoicingAddress);
				}
			}
		}

		private async Task HandleDeliveryAddressChangeAsync(ChangeEventArgs e)
		{
			if (int.TryParse(e.Value.ToString(), out int addressID))
			{
				if (addressID == 0)
				{
					order.DeliveryAddressID = -1;
					await ShowAddressCreateModalAsync((int)AddressType.DeliveryAddress);
				}
			}
		}

		private async Task HandleEditAddressButtonClickAsync(int addressType)
		{
			if ((int)AddressType.DeliveryAddress == addressType)
			{
				AddressDto address = deliveryAddresses.Find(i => i.ID == order.DeliveryAddressID);
				if (address is not null)
				{
					await ShowAddressUpdateModalAsync(address);
				}
			}
			else if ((int)AddressType.InvoicingAddress == addressType)
			{
				AddressDto address = invoicingAddresses.Find(i => i.ID == order.InvoicingAddressID);
				if (address is not null)
				{
					await ShowAddressUpdateModalAsync(address);
				}
			}
		}

		private async Task ShowAddressCreateModalAsync(int addressTypeID)
		{
			ModalOptions options = new()
			{
				DisableBackgroundCancel = true,
				Animation = ModalAnimation.FadeInOut(0.25),
				HideCloseButton = true
			};
			ModalParameters parameters = new();

			parameters.Add("ConfirmButtonText", "Vytvořit");
			parameters.Add("CancelButtonText", "Zrušit");
			parameters.Add("AddressIM", new AddressDto());

			ModalResult result = await Modal.Show<AddressCreateUpdateModal>("Vytvoření adresy", parameters, options).Result.ConfigureAwait(false);

			if (result.Cancelled)
			{
				return;
			}

			AddressDto address = (AddressDto)result.Data;
			address.AddressTypeID = addressTypeID;

			if (order.LoginAccount is not null)
			{
				address.UserEmail = order.LoginAccount.Email;
				AddressDto addressDto = await AddressFacadeContract.CreateUserAddressAsync(address);

				if (addressDto is not null && (int)AddressType.DeliveryAddress == addressDto.AddressTypeID)
				{
					deliveryAddresses.Add(addressDto);
					order.DeliveryAddressID = addressDto.ID;
				}
				else if (addressDto is not null && (int)AddressType.InvoicingAddress == addressDto.AddressTypeID)
				{
					invoicingAddresses.Add(addressDto);
					order.InvoicingAddressID = addressDto.ID;
				}
			}
			else
			{
				// vytvorit adresu bez login account
				// vytvarim pouze delivery adresu, protoze invoicing adresa musi byt (nemohu ji smazat a je vyzadovana pri vytvareni objednavky)

				AddressDto addressDto = await AddressFacadeContract.CreateAddressAsync(address);

				// vzdy bude vytvarena pouze dorucovaci adresa
				if (addressDto is not null && (int)AddressType.DeliveryAddress == addressDto.AddressTypeID)
				{
					deliveryAddresses = new() { addressDto };
					order.DeliveryAddressID = addressDto.ID;
					order.DeliveryAddress = addressDto; // kvuli moznemu odstraneni adresy, pokud admin vytvorit dorucovaci adresu, ale odesle formular bez dorucovaci adresy
				} // tento kod se nikdy nazavola
				else if (addressDto is not null && (int)AddressType.InvoicingAddress == addressDto.AddressTypeID)
				{
					invoicingAddresses.Add(addressDto);
					order.InvoicingAddressID = addressDto.ID;
				}
			}
		}

		private async Task ShowAddressUpdateModalAsync(AddressDto address)
		{
			ModalOptions options = new()
			{
				DisableBackgroundCancel = true,
				Animation = ModalAnimation.FadeInOut(0.25),
				HideCloseButton = true,
				ContentScrollable = true
			};
			ModalParameters parameters = new();

			parameters.Add("ConfirmButtonText", "Potvrdit");
			parameters.Add("CancelButtonText", "Zrušit");
			parameters.Add("AddressIM", address);

			ModalResult result = await Modal.Show<AddressCreateUpdateModal>("Editace adresy", parameters, options).Result.ConfigureAwait(false);

			if (result.Cancelled)
			{
				return;
			}

			AddressDto updatedDddress = (AddressDto)result.Data;

			if (order.LoginAccount is not null)
			{
				AddressDto addressDto = await AddressFacadeContract.UpdateUserAddressAsync(updatedDddress);

				if (addressDto is not null && (int)AddressType.DeliveryAddress == addressDto.AddressTypeID)
				{
					deliveryAddresses.RemoveAll(i => i.ID == updatedDddress.ID);
					deliveryAddresses.Add(addressDto);
					deliveryAddresses.OrderBy(i => i.ID);
					order.DeliveryAddressID = addressDto.ID;
				}
				else if (addressDto is not null && (int)AddressType.InvoicingAddress == addressDto.AddressTypeID)
				{
					invoicingAddresses.RemoveAll(i => i.ID == updatedDddress.ID);
					invoicingAddresses.Add(addressDto);
					invoicingAddresses.OrderBy(i => i.ID);
					order.InvoicingAddressID = addressDto.ID;
				}
			}
			else
			{
				//editovat adresu, ktera nema login account
				AddressDto addressDto = await AddressFacadeContract.UpdateAddressAsync(updatedDddress);

				if (addressDto is not null && (int)AddressType.DeliveryAddress == addressDto.AddressTypeID)
				{
					deliveryAddresses = new() { addressDto };
					//order.DeliveryAddressID = addressDto.ID; // zbytecne
				}
				else if (addressDto is not null && (int)AddressType.InvoicingAddress == addressDto.AddressTypeID)
				{
					invoicingAddresses = new() { addressDto };
					//order.InvoicingAddressID = addressDto.ID; // zbytecne
				}
			}
		}

		private async Task ShowAddOrderItemModalAsync()
		{
			ModalOptions options = new()
			{
				DisableBackgroundCancel = true,
				Animation = ModalAnimation.FadeInOut(0.25),
				HideCloseButton = true
			};
			ModalParameters parameters = new();

			parameters.Add("ConfirmButtonText", "Přidat");
			parameters.Add("CancelButtonText", "Zrušit");

			ModalResult result = await Modal.Show<AddOrderItemModal>("Přidání produktu do objednávky", parameters, options).Result.ConfigureAwait(false);

			if (result.Cancelled)
			{
				return;
			}

			OrderItemIM orderItemIM = (OrderItemIM)result.Data;

			// kontrolovat zdali neni jeden produkt vicekrat v objednavce
			// nebo nekontrolovat -> duvod: muzou byt rozdilne ceny u jednoho produktu
			if (orderItemIM is not null)
			{
				order.OrderItems.Add(orderItemIM);
			}
		}

		private string GetDeliveryTypeNameAndFee()
		{
			var deliveryType = DeliveryTypeState.Value.DeliveryTypes.Find(i => i.ID == order.DeliveryTypeID);

			return $"{deliveryType?.Name}: + {deliveryType?.Fee}";
		}

		private string GetPaymentTypeNameAndFee()
		{
			var paymentType = PaymentTypeState.Value.PaymentTypes.Find(i => i.ID == order.PaymentTypeID);

			return $"{paymentType?.Name}: + {paymentType?.Fee}";
		}

		private decimal CalculateOrderItemsPrice()
		{
			return Decimal.Round(order.OrderItems.Sum(i => i.Amount * i.Price), 2, MidpointRounding.AwayFromZero);
		}

		private decimal CalculateTotalOrderPrice()
		{
			serviceFee = DeliveryTypeState.Value.DeliveryTypes.Find(i => i.ID == order.DeliveryTypeID)?.Fee + PaymentTypeState.Value.PaymentTypes.Find(i => i.ID == order.PaymentTypeID)?.Fee;

			return CalculateOrderItemsPrice() + serviceFee.Value;
		}

		private async Task HandleSubmitAsync()
		{
			order.OrderID = OrderID;
			await OrderFacadeContract.UpdateOrderAsync(order).ConfigureAwait(false);

			ToastService.ShowSuccess("Změny uloženy!", "ÚSPĚCH");
		}
	}
}
