import * as React from "react";
import * as Yup from "yup";
import CreateAccountForm from "./Checkout/CreateAccountForm";
import DeliveryAddressForm from "./Checkout/DeliveryAddressForm";
import DeliveryAndPaymentTypeForm from "./Checkout/DeliveryAndPaymentTypeForm";
import Dropdown, { Option } from 'react-dropdown';
import InvoicingAddressForm from "./Checkout/InvoicingAddressForm";
import OrderSummary from "./Checkout/OrderSummary";
import { AddressController_GetUserAddresses, OrderController_CreateOrder, OrderController_GetDeliveryTypes, OrderController_GetPaymentTypes, OrderController_GetUserShoppingCartItems, ProductController_GetProduct } from "../../../apiClient/routes";
import { IDeliveryType, IPaymentType, IInvoicingAddress, IDeliveryAddress, IPassword, IShoppingCartItem, IProductItem, INewOrder, IAddress, AddressType, jwtToken } from "../../../apiModels/ViewModels";
import { Formik, Form } from "formik";
import { GetObject, GetShoppingCart, RemoveShoppingCartFromLocalStorage } from "../../../services/localStorageService";
import { Link, RouteComponentProps } from "react-router-dom";
import http from "../../../services/httpService";
import { toast } from "react-toastify";

interface IValues {
	invoicingAddress: IInvoicingAddress,
	deliveryAddress: IDeliveryAddress,
	password: IPassword,
	deliveryTypePicked: string,
	paymentTypePicked: string,
}

// data: string je zbytečné -> nikde není používáno
type CheckoutProps = RouteComponentProps<{ data: string }> & {
	getUserShoppingCart(user: jwtToken): void,
	clearShoppingCart(orderNumber: number, totalPrice: number): void
}

class Checkout extends React.Component<CheckoutProps> {
	state = {
		deliveryTypes: new Array<IDeliveryType>(),
		errorMessage: '',
		filteredPaymentTypes: new Array<IPaymentType>(),
		isLoggedIn: false,
		orderItems: Array<IShoppingCartItem>(),
		paymentTypes: new Array<IPaymentType>(),
		selectedDeliveryAddress: '',
		selectedDeliveryType: {
			id: 0,
			name: '',
			fee: 0
		},
		selectedInvoicingAddress: '',
		selectedPaymentType: {
			id: 0,
			name: '',
			fee: 0
		},
		showCreateAccountForm: false,
		showDeliveryAddressForm: false,
		showSelectPaymentType: false,
		userAddresses: Array<IAddress>(),
		userId: ''
	}

	async componentDidMount() {
		document.title = "Vytvoření objednávky";

		await http.get<IDeliveryType[]>(OrderController_GetDeliveryTypes).then(async response => {
			const deliveryTypes = await response.data;
			this.setState({ deliveryTypes });
		})
		.catch(e => {
			console.log(e);
			this.setState({ ...this.state });
		});

		await http.get<IPaymentType[]>(OrderController_GetPaymentTypes).then(async response => {
			const paymentTypes = await response.data;
			this.setState({ paymentTypes });
		})
		.catch(e => {
			console.log(e);
			this.setState({ ...this.state });
		});

		const user = GetObject();
		if (user !== null) { // get user and his order, order items and addresses
			await http.get<IAddress[]>(AddressController_GetUserAddresses(user.unique_name.toString())).then(async response => {
				const userAddresses = await response.data;
				this.setState({ userAddresses });
			});

			await http.get<IShoppingCartItem[]>(OrderController_GetUserShoppingCartItems(user.unique_name.toString())).then(async response => {
				const orderItems = await response.data;
				orderItems.sort((a, b) => a.name > b.name ? 1 : -1);
				this.setState({ orderItems, isLoggedIn: true, userId: user.unique_name });
			}).catch(e => {
				console.log(e);
				this.setState({ ...this.state });
			});

			// Musí být otestováno
			// Vybirani adres prihlaseneho uzivatele
			if (this.props.location?.state !== undefined) {
				const history = this.props.location.state;

				this.setState({
					selectedInvoicingAddress: history.invoicingAddress?.id !== undefined ? history.invoicingAddress.id.toString() : '',
					selectedDeliveryAddress: history.deliveryAddress?.id !== undefined ? history.deliveryAddress.id.toString() : ''
				});
			}

		} else { // else get items from localStorage
			const storageOrderItems = GetShoppingCart();

			if (storageOrderItems.length > 0) {
				let orderItems: IShoppingCartItem[] = [];

				await Promise.all(storageOrderItems.map(async i => {
					await http.get<IProductItem>(ProductController_GetProduct(i.productID.toString())).then(async response => {
						let product = await response.data;
						let orderItem: IShoppingCartItem = { // Mozna bude lepsi vytvorit samostatny model pro Checkout => CheckoutOrderItem misto IShoppingCartItem
							id: undefined,  // not needed
							productID: product.id,
							name: product.name,
							price: (product.reducedPrice !== undefined && product.reducedPrice > 0 && product.reducedPrice < product.price) ? product.reducedPrice : product.price,
							amount: i.amount,
							availableQuantity: product.availableQuantity, // not needed
							productCategoryID: product.productCategoryID,  // not needed?
							productCategoryName: product.productCategoryName, // not needed
							productImageID: product.productImageIDs[0] // not needed
						}
						orderItems.push(orderItem);
					})
					.catch(e => {
						console.log(e);
						this.setState({ ...this.state });
					});
				}));

				orderItems.sort((a, b) => a.name > b.name ? 1 : -1);
				this.setState({ orderItems });
			}
		}

		// Musí být otestováno
		this.setState({
			showDeliveryAddressForm: this.props.location?.state?.showDeliveryAddressForm ?? false,
			selectedDeliveryType: this.props.location?.state?.deliveryTypePicked ?? { id: 0, name: '', fee: 0 },
			selectedPaymentType: this.props.location?.state?.paymentTypePicked ?? { id: 0, name: '', fee: 0 },
			filteredPaymentTypes: this.props.location?.state?.filteredPaymentTypes ?? new Array<IPaymentType>(),
			showSelectPaymentType: this.props.location?.state?.showSelectPaymentType ?? false
		});
	}

	handleDeliveryAddressChange = (arg: Option): void => {
		this.setState({ selectedDeliveryAddress: arg.value });
	}

	handleDeliveryTypeChange = (item: IDeliveryType): void => {
		if (item.name === "Vyzvednutí na prodejně") {
			const paymentTypes = this.state.paymentTypes.filter(i => i.name !== "Dobírka").sort((a, b) => a.name > b.name ? 1 : -1);
			this.setState({ filteredPaymentTypes: paymentTypes, selectedDeliveryType: item, selectedPaymentType: paymentTypes.find(i => i.name === "Bankovní převod"), showSelectPaymentType: true });
		} else if (item.name === "Doručení námi") {
			const paymentTypes = this.state.paymentTypes.filter(i => i.name !== "Na prodejně").sort((a, b) => a.name > b.name ? 1 : -1);
			this.setState({ filteredPaymentTypes: paymentTypes, selectedDeliveryType: item, selectedPaymentType: paymentTypes.find(i => i.name === "Bankovní převod"), showSelectPaymentType: true });
		}
	}

	handleInvoicingAddressChange = (arg: Option): void => {
		this.setState({ selectedInvoicingAddress: arg.value });
	}

	handlePaymentTypeChange = (item: IPaymentType): void => {
		this.setState({ selectedPaymentType: item });
	}

	handleShowCreateAccountFormChange = (): void => {
		const { showCreateAccountForm } = this.state;
		this.setState({ showCreateAccountForm: !showCreateAccountForm });
	}

	handleShowDeliveryAddressFormChange = (): void => {
		const { showDeliveryAddressForm } = this.state;
		this.setState({ showDeliveryAddressForm: !showDeliveryAddressForm, selectedDeliveryAddress: '' });
	}

	handleSubmit = (formValues: IValues) => {
		const { orderItems, isLoggedIn, showCreateAccountForm, showDeliveryAddressForm, userId } = this.state;

		const data = {
			userId: isLoggedIn ? userId : null, // Natahnout email prihlaseneho uzivatele, jinak vratit prazny string
			invoicingAddress: formValues.invoicingAddress,
			deliveryAddress: showDeliveryAddressForm ? formValues.deliveryAddress : null,
			orderItems: orderItems.map(i => { return { productID: i.productID, amount: i.amount } }),
			password: showCreateAccountForm ? formValues.password : null,
			deliveryTypeID: formValues.deliveryTypePicked,
			paymentTypeID: formValues.paymentTypePicked
		};

		http.post<INewOrder>(OrderController_CreateOrder, data, { validateStatus: (status: number) => { return status <= 400 } }).then( async response => {
			if (response.status === 200) {
				// smazat kosik z local storage
				if (!isLoggedIn) {
					RemoveShoppingCartFromLocalStorage();
					// Problem s react state update on an unmounted component
					//this.props.clearShoppingCart();
				}

				toast.success(`Objednávka úspěšně vytvořena!`, {
					position: "top-right",
					autoClose: 3000,
					hideProgressBar: true,
					closeOnClick: true,
					pauseOnHover: false,
					draggable: true,
					progress: undefined,
				});


				const user = GetObject();
				if (user !== null) {
					this.props.getUserShoppingCart(user);
				}

				const orderNumber = await response.data.orderNumber;
				const totalPrice = await response.data.totalPrice;

				//this.props.clearShoppingCart(orderNumber, totalPrice);
				this.props.history.push("/order/successful", { orderNumber: response.data.orderNumber, totalPrice: response.data.totalPrice });
			} else {
				this.setState({ errorMessage: response.data.errorMessage });
				toast.error(`${response.data.errorMessage}`, {
					position: "top-right",
					autoClose: 3000,
					hideProgressBar: true,
					closeOnClick: true,
					pauseOnHover: false,
					draggable: true,
					progress: undefined,
				});
			}
		}).catch(e => {
			console.log(e);
			this.setState({ ...this.state });
		});
	}

	render() {
		const { deliveryTypes, errorMessage, filteredPaymentTypes, isLoggedIn, orderItems, selectedDeliveryAddress, selectedDeliveryType, selectedInvoicingAddress,
			selectedPaymentType, showCreateAccountForm, showDeliveryAddressForm, userAddresses, showSelectPaymentType } = this.state;

		const deliveryAddressValidationSchema = Yup.object().shape({
			deliveryAddress: Yup.object().shape({
				firstName: Yup.string().required("Jméno je vyžadováno!"),
				lastName: Yup.string().required("Příjmení je vyžadováno!"),
				phoneNumber: Yup.string().required("Telefonní číslo je vyžadováno!"),
				city: Yup.string().required("Město je vyžadováno!"),
				street: Yup.string().required("Ulice je vyžadována!"),
				zipCode: Yup.string().required("PSČ je vyžadováno!")
			})
		});

		const passwordValidationSchema = Yup.object().shape({
			password: Yup.object().shape({
				password: Yup.string()
					.required("Heslo je vyžadováno!")
					.min(8, "Heslo musí obsahovat nejméně 8 znaků!"),
				confirmPassword: Yup.string()
					.required("Potvrzení hesla je vyžadováno!")
					.min(8, "Heslo musí obsahovat nejméně 8 znaků!")
					.oneOf([Yup.ref('password'), null], "Hesla se neshodují!")
			})
		});

		let validationSchema = Yup.object().shape({
			invoicingAddress: Yup.object().shape({
				firstName: Yup.string().required("Jméno je vyžadováno!"),
				lastName: Yup.string().required("Příjmení je vyžadováno!"),
				email: Yup.string().required("Email je vyžadován!").email("Nevalidní emailová adresa!"),
				phoneNumber: Yup.string().required("Telefonní číslo je vyžadováno!"),
				city: Yup.string().required("Město je vyžadováno!"),
				street: Yup.string().required("Ulice je vyžadována!"),
				zipCode: Yup.string().required("PSČ je vyžadováno!")
			}),
			deliveryTypePicked: Yup.string().required("Vyberte způsob dopravy!"),
			paymentTypePicked: Yup.string().required("Vyberte způsob platby!")
		});

		if (showCreateAccountForm) {
			validationSchema = validationSchema.concat(passwordValidationSchema);
		}

		if (showDeliveryAddressForm) {
			validationSchema = validationSchema.concat(deliveryAddressValidationSchema);
		}

		// Empty (init) objects
		const invoicingAddress: IInvoicingAddress = {
			id: undefined,
			firstName: '',
			lastName: '',
			email: '',
			phoneNumber: '',
			city: '',
			street: '',
			zipCode: ''
		}

		const deliveryAddress: IDeliveryAddress = {
			id: undefined,
			firstName: '',
			lastName: '',
			phoneNumber: '',
			city: '',
			street: '',
			zipCode: ''
		}

		const password: IPassword = {
			password: '',
			confirmPassword: ''
		}
		// End of empty (init) objects

		return (
			<React.Fragment>
				<section className="checkout">
					<div className="container">
						<h3 className="mb-4">Vytvoření objednávky</h3>
						<h4>Mapa s oblastí doručení</h4>
						<iframe src="https://www.google.com/maps/d/embed?mid=1YBfeKo_95TG0zDl7VdZ_QFbvzP8VwtX6&ehbc=2E312F" width="100%" height="600"></iframe>
						<div className="checkout__form">
							{orderItems.length
								? <>
									<Formik
										initialValues={{
											invoicingAddress: (selectedInvoicingAddress === "0") ? { ...invoicingAddress } : (
												userAddresses.find(i => i.id.toString() === selectedInvoicingAddress) ||
												this.props.history.location.state?.invoicingAddress as IInvoicingAddress ||
												{ ...invoicingAddress }),
											deliveryAddress: selectedDeliveryAddress === "0" ? { ...deliveryAddress } : undefined ||
												userAddresses.find(i => i.id.toString() === selectedDeliveryAddress) ||
												{ ...this.props.history.location.state?.deliveryAddress } as IDeliveryAddress ||
												{ ...deliveryAddress },
											password: { ...password }, // spred operator zajisti skopirovani obsahu jednoho objektu do noveho objektu
											deliveryTypePicked: selectedDeliveryType.id !== 0 ? selectedDeliveryType.id.toString() : '',
											paymentTypePicked: selectedPaymentType.id !== 0 ? selectedPaymentType.id.toString() : '2' // Init hodnota Bankovni prevod
										}}
										enableReinitialize={true} // Bug: Změna adresy z dropdownu nebo změna způsobů (dopravy/platby) mi znovu inicializuje formulář
										validationSchema={validationSchema}
										onSubmit={(formValues: IValues) => this.handleSubmit(formValues)}>
										{({ touched, errors, handleReset, handleSubmit, setFieldTouched, handleChange, values, setValues, setFieldValue }) => (
											<Form onReset={handleReset} onSubmit={handleSubmit} noValidate >
												<DeliveryAndPaymentTypeForm
													deliveryTypes={deliveryTypes}
													paymentTypes={filteredPaymentTypes}
													selectedDeliveryType={selectedDeliveryType}
													showSelectPaymentType={showSelectPaymentType}
													onDeliveryTypeChange={this.handleDeliveryTypeChange}
													onPaymentTypeChange={this.handlePaymentTypeChange}
													errors={errors}
													setFieldTouched={setFieldTouched}
													setFieldValue={setFieldValue}
													handleChange={handleChange}
													touched={touched}
												/>

												<h4>Fakturační údaje</h4>
												<div className="row">
													<div className="col-lg-8 col-md-6">

														{isLoggedIn
															? <Dropdown
																className='my-dropdown-root' controlClassName='checkout__dropdown__control' placeholderClassName='my-dropdown-placeholder'
																menuClassName='my-dropdown-menu'
																placeholder='Uložené fakturační adresy'
																options={[...userAddresses.filter(i => i.addressTypeID === AddressType.InvoicingAddress).map(address => {
																	return {
																		value: address.id.toString(),
																		label: `${address.firstName}, ${address.lastName}, ${address.city}, ${address.street} ...`
																	}
																}), { value: '0', label: 'Nová fakturační adresa' }]
																}
																onChange={this.handleInvoicingAddressChange} value={selectedInvoicingAddress}
															/>
															: null
														}

														{errorMessage
															? <div className='error-message'>{errorMessage}</div>
															: null
														}

														<InvoicingAddressForm
															errors={errors.invoicingAddress}
															handleChange={handleChange}
															setFieldTouched={setFieldTouched}
															touched={touched.invoicingAddress}
															values={values.invoicingAddress}
														/>

														{isLoggedIn
															? null
															: <div className="checkout__input__checkbox">
																<label>
																	Vytvořit účet?
																	<input onChange={() => {
																		this.handleShowCreateAccountFormChange();
																		setValues({ ...values, password: password });
																	}} type="checkbox" checked={showCreateAccountForm} />
																	<span className="checkmark"></span>
																</label>
															</div>
														}

														{showCreateAccountForm && !isLoggedIn
															? <CreateAccountForm
																errors={errors.password}
																handleChange={handleChange}
																setFieldTouched={setFieldTouched}
																touched={touched.password}
																values={values.password}
															/>
															: null
														}

														<div className="checkout__input__checkbox">
															<label>
																Doručit na jinou adresu?
																<input onChange={() => {
																	this.handleShowDeliveryAddressFormChange();
																	setValues({ ...values, deliveryAddress: deliveryAddress });
																}} type="checkbox" checked={showDeliveryAddressForm} />
																<span className="checkmark"></span>
															</label>
														</div>

														{showDeliveryAddressForm
															? <React.Fragment>
																{isLoggedIn
																	? <Dropdown
																		className='my-dropdown-root' controlClassName='checkout__dropdown__control' placeholderClassName='my-dropdown-placeholder'
																		menuClassName='my-dropdown-menu'
																		placeholder='Uložené droručovací adresy'
																		options={[...userAddresses.filter(i => i.addressTypeID === AddressType.DeliveryAddress).map(address => {
																			return {
																				value: address.id.toString(),
																				label: `${address.firstName}, ${address.lastName}, ${address.city}, ${address.street} ...`
																			}
																		}), { value: '0', label: 'Nová doručovací adresa' }]
																		}
																		onChange={this.handleDeliveryAddressChange} value={selectedDeliveryAddress}
																	/>
																	: null
																}

																<DeliveryAddressForm
																	errors={errors.deliveryAddress}
																	handleChange={handleChange}
																	setFieldTouched={setFieldTouched}
																	touched={touched.deliveryAddress}
																	values={values.deliveryAddress}
																/>
															</React.Fragment>
															: null
														}

													</div>
													<div className="col-lg-4 col-md-6">
														<div className="checkout__order">
															<OrderSummary
																orderItems={orderItems}
																deliveryType={selectedDeliveryType}
																paymentType={selectedPaymentType}
															/>
															<button type="submit" className="site-btn">DOKONČIT OBJEDNÁVKU</button>
														</div>
													</div>
												</div>
												<Link to={{
													pathname: "/cart",
													state: {
														...values,
														showDeliveryAddressForm: showDeliveryAddressForm,
														showSelectPaymentType: showSelectPaymentType,
														filteredPaymentTypes: filteredPaymentTypes,
														deliveryTypePicked: selectedDeliveryType,
														paymentTypePicked: selectedPaymentType
													}
												}} className="checkout__link">Zpět do košíku</Link>
											</Form>
										)}
									</Formik>
								</>
								: null
							}
						</div>
					</div>
				</section>
			</React.Fragment>
		);
	}
}

export default Checkout;