import * as React from "react";
import ProductListHeader from "./products/productListHeader";
import ProductListItem from "./products/ProductListItem";
import { Pager } from "../../common/pager";
import { ProductController_GetProducts, ProductController_GetCategories } from "../../../apiClient/routes";
import { IPagedQueryResult, IProductCategoryItem, IProductItem, IProductListQueryFilter, ISortItem } from "../../../apiModels/ViewModels";
import http from "../../../services/httpService";
import { Option } from "react-dropdown";
import history from "../../../history";
import * as QueryString from 'query-string';
//const queryString = require('query-string');

type ProuductListProps = {
	onAddToCartClick(productId: number, amount: number): void,
	searchString: string
}

type ProductListState = {
	activeFilterExpression: IProductListQueryFilter,
	activePageSizeExpression: string,
	activeSortExpression: string,
	products: Array<IProductItem>,
	productCategories: Array<IProductCategoryItem>,
	selectedCategories: Array<IProductCategoryItem>,
	pageIndex: number,
	sortItem: ISortItem,
	totalPages: number,
	isLoaded: boolean
}

class ProductList extends React.Component<ProuductListProps, ProductListState> {
	constructor(props: ProuductListProps) {
		super(props);

		const parsed: any = QueryString.parse(window.location.search);

		this.state = {
			activeFilterExpression: {
				productCategoryId: parsed.category ?? '0',
				searchString: parsed.searchString ?? ''
			} as IProductListQueryFilter,
			activePageSizeExpression: parsed.productsOnPage ?? '8',
			activeSortExpression: parsed.sortValue ?? '1',
			products: Array<IProductItem>(),
			productCategories: Array<IProductCategoryItem>(),
			selectedCategories: Array<IProductCategoryItem>(),
			pageIndex: parsed.pageIndex ?? 0,
			sortItem: {
				direction: parsed.sortDirection ?? 'ascending',
				expression: parsed.sortExpression ?? 'Name'
			} as ISortItem,
			totalPages: 1,
			isLoaded: false
		}
	}

	async componentDidMount() {
		document.title = "Produkty";

		let allProducts = {} as IPagedQueryResult<IProductItem>;
		let allCategories = Array<IProductCategoryItem>();
		let pagedQuery = {
			filter: this.state.activeFilterExpression,
			pageIndex: this.state.pageIndex,
			pageSize: this.state.activePageSizeExpression,
			sorting: [this.state.sortItem]
		};

		await http.post<IPagedQueryResult<IProductItem>>(ProductController_GetProducts, pagedQuery).then((response) => {
			allProducts = response.data;
			this.calculateTotalPages(response.data.totalCount);
		})
		.catch(e => {
			console.log(e);
			this.setState({ ...this.state });
		});

		await http.get<IProductCategoryItem[]>(ProductController_GetCategories).then((response) => {
			allCategories = response.data;
		})
		.catch(e => {
			console.log(e);
			this.setState({ ...this.state });
		});

		this.setState({
			activeFilterExpression: { ...this.state.activeFilterExpression, searchString: this.props.searchString },
			products: allProducts.data,
			productCategories: allCategories,
			isLoaded: true
		});
	}

	componentDidUpdate(prevProps: ProuductListProps, prevState: ProductListState) {
		if (this.state.activeFilterExpression !== prevState.activeFilterExpression ||
			this.state.pageIndex !== prevState.pageIndex ||
			this.state.activePageSizeExpression !== prevState.activePageSizeExpression ||
			this.state.sortItem !== prevState.sortItem ||
			this.props.searchString !== prevProps.searchString) {
			const { activeFilterExpression, activePageSizeExpression, pageIndex, sortItem } = this.state;
			let allProducts = {} as IPagedQueryResult<IProductItem>;
			let pagedQuery = {
				filter: { ...activeFilterExpression, searchString: this.props.searchString } as IProductListQueryFilter,
				pageIndex: pageIndex,
				pageSize: activePageSizeExpression,
				sorting: [sortItem]
			};
			
			http.post<IPagedQueryResult<IProductItem>>(ProductController_GetProducts, pagedQuery).then((response) => {
				allProducts = response.data;
				this.calculateTotalPages(allProducts.totalCount);
				this.setState({ products: allProducts.data, isLoaded: true });
			})
			.catch(e => {
				console.log(e);
				this.setState({ ...this.state });
			});
		}
	}

	calculateTotalPages = (productsAmount: number): void => {
		let pageSize = Number(this.state.activePageSizeExpression);
		let totalPages = Math.floor(productsAmount / pageSize);

		if ((productsAmount % pageSize) > 0) {
			totalPages++;
			this.setState({ totalPages });
		} else if (productsAmount === 0) {
			this.setState({ totalPages: 0 });
		} else if (totalPages <= this.state.pageIndex) {
			this.setState({ pageIndex: 0 });
		} else {
			this.setState({ totalPages });
		}
	}

	handleFilterExpressionChange = (categoryId: number): void => {
		let category = this.state.productCategories.find(i => i.id === categoryId);
		let selectedCategories: IProductCategoryItem[] = [];
		if (category !== undefined) {
			selectedCategories = this.getProductCategoryParent(category).reverse();
		}

		this.handleQueryStringChange([
			{propertyName: 'category', value: category?.id},
			{propertyName: 'pageIndex', value: 0},
		]);
		this.setState({ activeFilterExpression: { ...this.state.activeFilterExpression, productCategoryId: categoryId.toString() }, selectedCategories, pageIndex: 0 });
	}

	getProductCategoryParent = (category: IProductCategoryItem): IProductCategoryItem[] => {
		let result = [category];

		if (category.parentID !== -1) {
			let parent = this.state.productCategories.find(i => i.id === category.parentID);

			if (parent !== undefined) {
				result.push(...this.getProductCategoryParent(parent));
			}

			return result;
		}

		return result;
	}

	// Při změně zobrazit první stránku (pageIndex 0)
	// Lepší řešení mě nenapadlo
	handlePageSizeExpressionChange = (arg: Option): void => {
		this.handleQueryStringChange([
			{propertyName: 'productsOnPage', value: arg.value},
			{propertyName: 'pageIndex', value: 0},
		]);
		this.setState({ activePageSizeExpression: arg.value.toString(), pageIndex: 0 });
	}

	handleSortExpressionChange = (arg: Option): void => {
		switch (arg.label) {
			case 'A-Z':
				this.handleQueryStringChange([
					{propertyName: 'sortDirection', value: 'ascending'},
					{propertyName: 'sortExpression', value: 'Name'},
					{propertyName: 'sortValue', value: arg.value}
				]);
				this.setState({
					activeSortExpression: arg.value,
					sortItem: {
						direction: 'ascending',
						expression: 'Name'
					}
				});
				break;
			case 'Z-A':
				this.handleQueryStringChange([
					{propertyName: 'sortDirection', value: 'descending'},
					{propertyName: 'sortExpression', value: 'Name'},
					{propertyName: 'sortValue', value: arg.value}
				]);
				this.setState({
					activeSortExpression: arg.value,
					sortItem: {
						direction: 'descending',
						expression: 'Name'
					}
				});
				break;
			case 'Nejdražší':
				this.handleQueryStringChange([
					{propertyName: 'sortDirection', value: 'descending'},
					{propertyName: 'sortExpression', value: 'Price'},
					{propertyName: 'sortValue', value: arg.value}
				]);
				this.setState({
					activeSortExpression: arg.value,
					sortItem: {
						direction: 'descending',
						expression: 'Price'
					}
				});
				break;
			case 'Nejlevnější':
				this.handleQueryStringChange([
					{propertyName: 'sortDirection', value: 'ascending'},
					{propertyName: 'sortExpression', value: 'Price'},
					{propertyName: 'sortValue', value: arg.value}
				]);
				this.setState({
					activeSortExpression: arg.value,
					sortItem: {
						direction: 'ascending',
						expression: 'Price'
					}
				});
				break;
			default:
				break;
		}
	}

	handlePageChange = (newPageIndex: number): void => {
		this.handleQueryStringChange([{ propertyName: 'pageIndex', value: newPageIndex }]);
		this.setState({ pageIndex: newPageIndex });
	}

	handlePageShift = (shift: number): void => {
		const { pageIndex, totalPages} = this.state;

		if (shift === 1) {
			if ((pageIndex + 1) < totalPages) {
				this.handleQueryStringChange([{ propertyName: 'pageIndex', value: (pageIndex + 1) }]);
				this.setState({ pageIndex: pageIndex + 1 });
			}
		}else {
			if ((pageIndex - 1) >= 0) {
				this.handleQueryStringChange([{ propertyName: 'pageIndex', value: (pageIndex - 1) }]);
				this.setState({ pageIndex: pageIndex - 1 });
			}
		}
	}

	handleQueryStringChange = (params: {propertyName: string, value: number | string | undefined}[]): void => {
		const parsed: any = QueryString.parse(window.location.search);
		let query = { ...parsed };

		params.forEach((item) => {
			query = { ...query, [item.propertyName]: item.value}
		});

		const stringified = QueryString.stringify(query);
		history.replace({
			pathname: history.location.pathname,
			search: '?' + stringified
		});
	}

	render() {
		const { activeFilterExpression,
			activePageSizeExpression,
			activeSortExpression,
			isLoaded,
			pageIndex,
			products,
			productCategories,
			selectedCategories,
			totalPages } = this.state;
		const { onAddToCartClick } = this.props;

		return (
			<React.Fragment>
				{isLoaded && products !== undefined
					? <section className="featured">
						<div className="container">

							<ProductListHeader
								activeFilterExpression={activeFilterExpression.productCategoryId!.toString()}
								activeSortExpression={activeSortExpression}
								activePageSizeExpression={activePageSizeExpression}
								categories={[...productCategories]}
								onFilterExpressionChange={this.handleFilterExpressionChange}
								onPageSizeExpressionChange={this.handlePageSizeExpressionChange}
								onSortExpressionChange={this.handleSortExpressionChange}
								productItemsAmount={products.length}
								selectedCategories={selectedCategories}
							/>

							<div className="row featured__filter">
								{products.map((product: IProductItem) => {
									return <ProductListItem key={`productListItem-${product.id}`}
										onAddToCartClick={onAddToCartClick}
										product={product}
									/>
								})}
							</div>

							<Pager
								onPageChange={this.handlePageChange}
								onPageShift={this.handlePageShift}
								pageIndex={pageIndex}
								totalPages={totalPages}
							/>

						</div>
					</section>
					: null
				}
			</React.Fragment>
		);
	}
}

export default ProductList;