import * as React from "react";
import { Redirect, Route } from "react-router";
import { RouteComponentProps } from "react-router-dom";
import AboutUs from "../components/User/components/AboutUs";
import AccountInfo from "../components/User/components/Account/AccountInfo";
import { AccountHeader } from "../components/User/components/Account/AccountHeader";
import AddressManagement from "../components/User/components/Account/AddressManagement";
import ChangePassword from "../components/User/components/Account/ChangePasswordForm";
import Contacts from "../components/User/components/Contacts";
import Checkout from "../components/User/components/checkout";
import Delivery from "../components/User/components/Delivery";
import Login from "../components/User/components/Security/Login";
import OrderCompleted from "../components/User/components/OrderCompleted";
import OrderDetail from "../components/User/components/Account/OrderDetail";
import OrderList from "../components/User/components/Account/OrderList";
import { PasswordRecovery } from "../components/User/components/Security/PasswordRecovery";
import PasswordReset from "../components/User/components/Security/PasswordReset";
import ProductList from "../components/User/components/productList";
import ProductDetail from "../components/User/components/productDetail";
import ShoppingCart from "../components/User/components/shoppingCart";
import Signup from "../components/User/components/Security/Signup";
import TradeTerms from "../components/User/components/TradeTerms";
import UserLayout from "../components/userLayout";
import {
	AddItemToShoppingCart, DeleteAuthorizationToken, DeleteCartItem, GetObject, GetShoppingCart, DecreaseCartItemAmount,
	IsCustomerLoggedIn, SetAuthorizationTokenLocalStorage
} from "../services/localStorageService";
import { ILoginIM, IProductItem, IShoppingCartItem, IShoppingCartStorageItem, jwtToken } from "../apiModels/ViewModels";
import { toast } from "react-toastify";
import {
	AccountController_AuthenticateUser, OrderController_AddOrderItem, OrderController_DeleteOrderItem,
	OrderController_GetUserShoppingCartItems, OrderController_RemoveOrderItem, ProductController_GetProduct
} from "../apiClient/routes";
import http from "../services/httpService";


class UserRoutes extends React.Component<RouteComponentProps> {
	state = {
		cartItemsCount: 0,
		cartItems: Array<IShoppingCartItem>(),
		displayErrorMessage: false,
		userName: '',
		searchString: ''
	}

	// If user is logged in, then get his shopping cart items, else try to load cart items from the local storage
	async componentDidMount() {
		const user = GetObject();
		if (user !== null) {
			 await this.getUserShoppingCart(user);
		} else {
			await this.getAnonymousShoppingCart();
		}
	}

	getUserShoppingCart = async (user: jwtToken): Promise<void> => {
		await http.get<IShoppingCartItem[]>(OrderController_GetUserShoppingCartItems(user.unique_name.toString())).then((response) => {
			this.setState({ cartItemsCount: response.data.length, cartItems: response.data, displayErrorMessage: false, userName: `${user.firstName || 'Účet'} ${user.lastName}` });
		}).catch(e => {
			console.log(e);
			this.setState({ ...this.state });
		});
	}

	async getAnonymousShoppingCart(): Promise<void> {
		const storageCartItems = GetShoppingCart();
		let cartItems: IShoppingCartItem[] = [];

		if (storageCartItems.length > 0) {
			await Promise.all(storageCartItems.map(async i => {
				await http.get<IProductItem>(ProductController_GetProduct(i.productID.toString())).then(async response => {
					const product = await response.data;
					const cartItem: IShoppingCartItem = {
						id: 0,
						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,
						productCategoryID: product.productCategoryID,
						productCategoryName: product.productCategoryName,
						productImageID: product.productImageIDs[0]
					}
					cartItems.push(cartItem);
				})
					.catch(e => {
						console.log(e);
						this.setState({ ...this.state });
					});
			}));
		}

		this.setState({ cartItems, cartItemsCount: storageCartItems.length, userName: '' });
	}

	// Adds new product to the cart or raise the amount of already existing product in the cart
	handleAddToCart = async (productId: number, amount: number): Promise<void> => {
		const { cartItemsCount } = this.state;
		const cartItems = [...this.state.cartItems]; // copy of state array (we don't want to change directly the state array)
		const cartItem: IShoppingCartStorageItem = {
			productID: productId,
			amount: amount
		}
		let errorMessage = '';

		// asi bude rozumne se prvne dotazat, jestli je mozne produkt pridat do kosiku (je skladem) a az pote ho pridat

		const user = GetObject();
		if (user !== null) {
			Promise.resolve( await http.post<{ amount: number }>(OrderController_AddOrderItem(user.unique_name.toString()), cartItem, { validateStatus: (status: number) => { return status <= 400 } }).then((response) => {
				if (response.status == 200) {
					//console.log('Pridano do kosiku (prihlaseny uzivatel): ', response.data);
					this.setState({ cartItemsCount: response.data.amount });
				} else {
					errorMessage = 'Chyba';

					toast.error(`Omlouváme se, ale tato položka již není skladem!`, {
						position: "top-right",
						autoClose: 3000,
						hideProgressBar: true,
						closeOnClick: true,
						pauseOnHover: false,
						draggable: true,
						progress: undefined,
					});
				}
			}).catch(e => {
				console.log(e);
				this.setState({ ...this.state });
			}));
		} else { // neotestovano
			AddItemToShoppingCart(cartItem); // add item to local storage
			//console.log("Pridano do local storage (neprihlaseny uzivatel)");
		}

		if (!errorMessage) {
			const item = cartItems.find(i => i.productID === productId);
			if (item !== undefined) { // if the item is already in shopping cart
				const index = cartItems.indexOf(item); // find his index
				cartItems[index] = { ...item }; // make copy of item object
				cartItems[index].amount += amount; // change the amount

				this.setState({ cartItems }); // save new array

				if (this.props.history.location.pathname !== "/cart") {
					toast.success(`👍 Položka "${cartItems.find(i => i.productID === productId)?.name}" byla vložena do košíku!`, {
						position: "top-right",
						autoClose: 3000,
						hideProgressBar: true,
						closeOnClick: true,
						pauseOnHover: false,
						draggable: true,
						progress: undefined,
					});
				}
				
				//console.log("Pridan item, ktery je jiz v kosiku (zvysil se pouze pocet kusu v kosiku)");
			} else { // item is not in the array => load it from server
				http.get<IProductItem>(ProductController_GetProduct(productId.toString())).then(response => {
					const product = response.data;
					const cartItem: IShoppingCartItem = {
						id: 0,
						productID: product.id,
						name: product.name,
						price: (product.reducedPrice != undefined && product.reducedPrice > 0 && product.reducedPrice < product.price) ? product.reducedPrice : product.price,
						amount: amount,
						availableQuantity: product.availableQuantity,
						productCategoryID: product.productCategoryID,
						productCategoryName: product.productCategoryName,
						productImageID: product.productImageIDs[0]
					}
					cartItems.push(cartItem);
					this.setState({ cartItems, cartItemsCount: (cartItemsCount + 1) });
					//console.log("Pridan item, ktery jeste neni v kosiku (produkt nacten ze serveru a vlozen do pole)");

					toast.success(`👍 Položka "${cartItems.find(i => i.productID === productId)?.name}" byla vložena do košíku!`, {
						position: "top-right",
						autoClose: 3000,
						hideProgressBar: true,
						closeOnClick: true,
						pauseOnHover: false,
						draggable: true,
						progress: undefined,
					});
				})
				.catch(e => {
					console.log(e);
					this.setState({ ...this.state });
				});
			}
		}
	}

	// Deletes an item from the shopping cart
	handleDeleteFromCart = (productId: number): void => {
		const { cartItems } = this.state;
		const cartItem = {
			productID: productId,
			amount: 0
		}

		const user = GetObject();
		if (user !== null) {
			http.post<{ amount: number }>(OrderController_DeleteOrderItem(user.unique_name.toString()), cartItem, { validateStatus: (status: number) => { return status <= 400 } }).then((response) => {
				if (response.status == 200) {
					//console.log('Smazano z kosiku (prihlaseny uzivatel): ', response.data);
				}
			}).catch(e => {
				console.log(e);
				this.setState({ ...this.state });
			});
		} else {
			DeleteCartItem(cartItem);
		}

		const filteredCartItems = cartItems.filter(i => i.productID !== productId);
		this.setState({ cartItems: filteredCartItems, cartItemsCount: filteredCartItems.length });
	}

	// Removes one amount of an item in the shopping cart or deletes it if the amount is <= 0
	handleRemoveFromCart = (productId: number, amount: number): void => {
		const cartItems = [...this.state.cartItems]; // copy of state array (we don't want to change directly the state array)
		const cartItem: IShoppingCartStorageItem = {
			productID: productId,
			amount: amount // amount should be always 1
		}

		const item = cartItems.find(i => i.productID === productId);
		if (item !== undefined) { // if the item is in the shopping cart
			if ((item.amount - amount) <= 0) { // delete product
				this.handleDeleteFromCart(productId);
			} else { // remove one amount
				const user = GetObject();
				if (user !== null) {
					http.post<{ amount: number }>(OrderController_RemoveOrderItem(user.unique_name.toString()), cartItem, { validateStatus: (status: number) => { return status <= 400 } }).then((response) => {
						if (response.status == 200) {
							//console.log('Snizeno mnozstvi produktu v kosiku (prihlaseny uzivatel): ', response.data);
							//this.setState({ cartItemsCount: response.data.amount }); // only amount changed so no need to update cartItemsCount
						}
					}).catch(e => {
						console.log(e);
						this.setState({ ...this.state });
					});
				} else {
					DecreaseCartItemAmount(cartItem); // change amount of item in local storage
					//console.log("Zmenen pocet kusu v local storage (neprihlaseny uzivatel)");
				}

				const index = cartItems.indexOf(item); // find his index
				cartItems[index] = { ...item }; // make copy of item object
				cartItems[index].amount -= amount; // change the amount

				this.setState({ cartItems }); // save new array
				//console.log("Odecteno mnozstvi produktu, ktery je jiz v kosiku (snizil se pouze pocet kusu v kosiku)");
			}
		}
	}

	handleSearchClick = (searchString: string): void => {
		this.setState({ searchString });
		if (this.props.history.location.pathname !== '/') {
			this.props.history.push('/');
		}
	}

	// Sets authorization token to the local storage and axios header
	handleLoginClick = (values: ILoginIM): void => {
		http.post(AccountController_AuthenticateUser, values, { validateStatus: status => { return status <= 400 } }).then((response) => {
			if (response.status == 200) {
				SetAuthorizationTokenLocalStorage(response.data);

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

				this.props.history.push("/");
			} else if (response.status == 400) {
				this.setState({ displayErrorMessage: true });
			}
		}).catch(e => {
			console.log(e);
			this.setState({ ...this.state });
		});
	}

	// Deletes authorization token from the local storage and axios header
	handleLogoutClick = (e: React.MouseEvent<HTMLAnchorElement, MouseEvent>): void => {
		DeleteAuthorizationToken();

		this.getAnonymousShoppingCart();
		this.props.history.push('/login');
	}

	handleClearShoppingCart = (): void => {
		this.setState({ cartItemsCount: 0, cartItems: new Array<IShoppingCartItem>() });
	}

	render() {
		const { cartItems, cartItemsCount, displayErrorMessage, searchString, userName } = this.state;
		cartItems.sort(function (a, b) { return a.name < b.name ? -1 : 1 });

		return (
			<UserLayout cartItemsAmount={cartItemsCount} onLogoutClick={this.handleLogoutClick} onSearchClick={this.handleSearchClick} userName={userName}>
				<Route exact path="/" render={() => <ProductList onAddToCartClick={this.handleAddToCart} searchString={searchString} />}  />

				<Route path="/aboutus" render={() => <AboutUs />} />
				<Route path="/account">
					{IsCustomerLoggedIn()
						? <AccountHeader>
							<Route path="/account/info" component={AccountInfo} />
							<Route path="/account/addresses" component={AddressManagement} />
							<Route path="/account/order/:id" render={(props: RouteComponentProps<{ id: string }>) =>
								<OrderDetail {...props} />} />
							<Route path="/account/orders" component={OrderList} />
							<Route path="/account/passwordChange" component={ChangePassword} />
						</AccountHeader>
						: <Redirect to="/login" />
					}
				</Route>

				<Route path="/cart" render={(props: RouteComponentProps) =>
					<ShoppingCart
						{...props}
						cartItems={cartItems}
						onAddToCartClick={this.handleAddToCart}
						onDeleteFromCartClick={this.handleDeleteFromCart}
						onRemoveFromCartClick={this.handleRemoveFromCart}
					/>}
				/>
				<Route path="/contacts" render={() => <Contacts />} />
				<Route path="/checkout" component={(props: RouteComponentProps<{ data: string }>) =>
					<Checkout {...props} getUserShoppingCart={this.getUserShoppingCart} clearShoppingCart={this.handleClearShoppingCart} />} />
				<Route path="/delivery" render={() => <Delivery />} />
				<Route path="/tradeterms" render={() => <TradeTerms />} />
				<Route path="/login" render={(props: any) => {
					if (IsCustomerLoggedIn()) {
						return <Redirect to="/" />
					} else {
						return <Login {...props} displayErrorMessage={displayErrorMessage} onSubmitClick={this.handleLoginClick} />
					}
				}} />
				<Route path="/order/successful" render={(props: any) => <OrderCompleted {...props} clearShoppingCart={this.handleClearShoppingCart} />} />
				<Route path="/passwordRecovery" render={(props: RouteComponentProps) => <PasswordRecovery {...props} />} />
				<Route path="/passwordReset/:token" component={PasswordReset} />
				<Route path="/product/:id" render={(props: RouteComponentProps<{ id: string }>) =>
					<ProductDetail {...props} onAddToCartClick={this.handleAddToCart} />}
				/>
				<Route path="/signup" component={(props: RouteComponentProps) => <Signup {...props} />} />
			</UserLayout>
		);
	}
}

export default UserRoutes;