import { useEffect, useState } from "react";
import { connect } from "react-redux";

import { sites, structuredData } from "@ax/api";
import { AsyncSelect, Button, Loader, Pagination, SearchField, Select } from "@ax/components";
import { getStructuredDataTitle, isReqOk } from "@ax/helpers";
import { LOCALE } from "@ax/locales";
import type { IContentType, IGetSitePagesParams, IGlobalLanguage, IPage, IRootState, ISite } from "@ax/types";

import SelectionListItem from "./SelectionListItem";

import * as S from "./style";

const PageFinder = (props: IPageFinderProps): JSX.Element => {
	const { onClick, currentSiteID, isOpen, allSites, lang, globalLangs, multiple, hideSites, pages } = props;

	const langOptions = globalLangs.map((lang) => ({ label: lang.label, value: lang.id.toString() }));

	const initialState: IState = {
		site: currentSiteID || allSites[0].id,
		lang: lang.id,
		type: "all",
		items: [],
		page: 1,
		totalItems: 0,
	};

	const [state, setState] = useState<IState>(initialState);
	const [isLoading, setIsLoading] = useState(false);
	const [selectedPages, setSelectedPages] = useState<IPage[]>([]);
	const [selectedPagesIds, setSelectedPagesIds] = useState<number[]>(pages ? pages : []);
	const [showSelected, setShowSelected] = useState(false);
	const [searchQuery, setSearchQuery] = useState<string>("");

	const defultTypeOptions = [
		{ label: "All content", value: "all" },
		{ label: "Base templates", value: "basic" },
		{ label: "List pages", value: "list" },
		{ label: "Static pages", value: "static" },
	];

	const [contentTypeOptions, setContentTypeOptions] = useState<{ label: string; value: string }[]>(defultTypeOptions);

	const changeContentTypeOptions = (types: { label: string; value: string }[]) =>
		setContentTypeOptions([...defultTypeOptions, ...types]);

	const itemsPerPage = 50;

	const resetQuery = () => {
		setSearchQuery("");
		setPage(1);
	};

	const changeState = (key: string, value: string | number | null) => setState((state) => ({ ...state, [key]: value }));

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useEffect(() => {
		if (!isOpen) resetQuery();
	}, [isOpen]);

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useEffect(() => {
		let isMounted = true;
		const params: IGetSitePagesParams = {
			deleted: false,
			filterPages: selectedPagesIds,
			siteID: state.site || "global",
			ignoreLang: true,
		};

		const getSelectedItems = async () => {
			if (!isMounted) return;

			const response: { status: number; data: { totalItems: number; items: IPage[] } } =
				await sites.getSitePages(params);

			if (isReqOk(response.status)) {
				setSelectedPages(response.data.items);
			} else {
				console.log("Error en getSelectedItems");
			}
		};

		if (selectedPagesIds && selectedPagesIds.length > 0) {
			getSelectedItems();
		}

		return function cleanup() {
			isMounted = false;
		};
	}, []);

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useEffect(() => {
		let isMounted = true;

		const isTypeFilter = (value: string) => ["basic", "list", "static"].includes(value);

		const params: IGetSitePagesParams = {
			siteID: state.site || "global",
			deleted: false,
			page: state.page,
			itemsPerPage,
			query: searchQuery,
			lang: state.lang,
			filterStructuredData: isTypeFilter(state.type) ? "all" : state.type,
			format: "list",
		};

		const filterQuery = isTypeFilter(state.type) ? `&type=${state.type}` : "";

		const getAndSetItems = async () => {
			if (!isMounted) return;

			setIsLoading(true);
			const response: { status: number; data: { totalItems: number; items: IPage[] } } = await sites.getSitePages(
				params,
				filterQuery,
			);
			if (isReqOk(response.status)) {
				setState((state) => ({ ...state, items: response.data.items, totalItems: response.data.totalItems }));
			} else {
				console.error("Error en getAndSetItems");
			}
			setIsLoading(false);
		};
		getAndSetItems();

		return function cleanup() {
			isMounted = false;
		};
	}, [currentSiteID, searchQuery, state.page, state.lang, state.site, state.type]);

	const getAndSetContentTypes = async () => {
		const { site, lang } = state;
		const { data } = await structuredData.getContentTypes(site, lang);
		const contentTypes = data.items
			? data.items.map((type: IContentType) => ({ label: type.title, value: type.id }))
			: [];
		changeContentTypeOptions(contentTypes);
		changeState("type", "all");
	};

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useEffect(() => {
		getAndSetContentTypes();
	}, [state.site]);

	const setPage = (newPage: number) => changeState("page", newPage);

	const handleChange = (item: { value: IPage; isChecked: boolean }) => {
		const { value, isChecked } = item;

		let newSelection: IPage[] = [...selectedPages];
		if (isChecked) {
			newSelection.push(value);
		} else {
			newSelection = newSelection.filter((page: IPage) => page.id !== value.id);
		}

		const newSelectionIDs = newSelection.map((page: IPage) => page.id);

		setSelectedPages(newSelection);
		setSelectedPagesIds(newSelectionIDs);

		if (showSelected && newSelection.length === 0) {
			setShowSelected(false);
		}
	};

	const handleSelectedClick = () => setShowSelected(!showSelected);

	const handleButtonClick = () => onClick(selectedPages);

	const handleSearch = (query: string) => {
		setSearchQuery(query);
		setPage(1);
	};

	const getPageList = (items: IPage[]) =>
		items?.map((page: IPage) => (
			<SelectionListItem
				option={page}
				key={page.id}
				title={page.title}
				type={getStructuredDataTitle(page.structuredData)}
				date={page.modified}
				onClick={onClick}
				pageID={page.id}
				isSelected={selectedPagesIds.includes(page.id)}
				onChange={handleChange}
				multiple={multiple}
				slug={page.slug.replace(/^\//, "")}
			/>
		));

	const showPagination = state.totalItems > itemsPerPage;

	const buttonText = !showSelected ? `view selected (${selectedPages.length})` : "hide selected";

	return (
		<S.Wrapper>
			<S.LanguageSiteFilters>
				<Select
					name="select"
					options={langOptions}
					onChange={(value) => changeState("lang", value)}
					value={state.lang.toString()}
					type="inline"
					mandatory={true}
				/>
				{!hideSites && (
					<AsyncSelect
						name="select"
						entity="sites"
						onChange={(value) => changeState("site", value)}
						value={state.site}
						type="inline"
						mandatory={true}
					/>
				)}
				{selectedPages.length > 0 && (
					<S.ButtonWrapper>
						<Button type="button" buttonStyle="text" onClick={handleSelectedClick}>
							{buttonText}
						</Button>
					</S.ButtonWrapper>
				)}
			</S.LanguageSiteFilters>
			<S.ContentTypeFilter>
				<S.Text>{LOCALE.common.filterByPageType}</S.Text>
				<Select
					name="select"
					options={contentTypeOptions}
					onChange={(value) => changeState("type", value)}
					value={state.type}
					mandatory
				/>
			</S.ContentTypeFilter>
			<S.SearchWrapper>
				<SearchField
					onChange={handleSearch}
					placeholder="Search"
					value={searchQuery}
					searchOnEnter={false}
					focus={false}
				/>
			</S.SearchWrapper>
			<S.LowText>Most recent content</S.LowText>
			{isLoading ? (
				<S.LoadingWrapper>
					<Loader name="circle" />
				</S.LoadingWrapper>
			) : (
				<S.ListWrapper>
					<S.PageList>{getPageList(showSelected ? selectedPages : state.items)}</S.PageList>
					<S.PaginationWrapper>
						{showPagination && (
							<Pagination
								size="S"
								setPage={setPage}
								totalItems={state.totalItems}
								itemsPerPage={itemsPerPage}
								currPage={state.page}
							/>
						)}
					</S.PaginationWrapper>
				</S.ListWrapper>
			)}
			{selectedPages.length > 0 && (
				<S.ActionWrapper>
					<Button type="button" onClick={handleButtonClick}>
						Add pages
					</Button>
				</S.ActionWrapper>
			)}
		</S.Wrapper>
	);
};

interface IState {
	site: number | null;
	lang: number;
	type: string;
	items: IPage[];
	page: number;
	totalItems: number;
}

interface IPageFinderProps {
	onClick: (value: IPage | IPage[]) => void;
	currentSiteID: number | null;
	isOpen: boolean;
	allSites: ISite[];
	lang: { locale: string; id: number };
	globalLangs: IGlobalLanguage[];
	multiple?: boolean;
	hideSites?: boolean;
	pages?: number[];
}

const mapStateToProps = (state: IRootState) => ({
	currentSiteID: state.sites.currentSiteInfo?.id || null,
	allSites: state.sites.sites,
	lang: state.app.lang,
	globalLangs: state.app.globalLangs,
});

export default connect(mapStateToProps)(PageFinder);
