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

import { structuredData } from "@ax/api";
import { AsyncSelect, Button, Loader, Select, TextField } from "@ax/components";
import { isReqOk } from "@ax/helpers";
import { useDebounce } from "@ax/hooks";
import type { IGetStructuredDataParams, ILanguage, IRootState, IStructuredDataContent } from "@ax/types";

import { useReference } from "../Context";
import Item from "./Item";

import * as S from "./style";

const ManualPanel = (props: IProps) => {
	const { onChange, currentSite, hasMaxItems, handleValidation, validators, lang, globalLangs, maxItems } = props;

	const { state, setState } = useReference();

	const [isLoading, setIsLoading] = useState(false);
	const initForm: IFormState = {
		source: state.sourceTitles[0]?.id,
		lang: lang.id,
		site: typeof state.site === "number" ? state.site : currentSite,
	};
	const [form, setForm] = useState(initForm);
	const debouncedSearch = useDebounce(state.search);

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

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useEffect(() => {
		let isMounted = true;
		const params: IGetStructuredDataParams = {
			dataID: form.source,
			page: 1,
			itemsPerPage: 50,
			pagination: true,
			deleted: false,
			include_draft: false,
			query: debouncedSearch,
			lang: form.lang,
		};

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

			setIsLoading(true);
			const siteID = form.site ? form.site : currentSite;
			const response: { status: number; data: { totalItems: number; items: IStructuredDataContent[] } } =
				await structuredData.getDataContents(params, siteID);
			if (isReqOk(response?.status)) {
				const { items } = response.data;
				setState((state) => ({ ...state, items }));
			} else {
				console.log("Error en getAndSetItems");
			}
			setIsLoading(false);
		};
		form.source && getAndSetItems();

		return function cleanup() {
			isMounted = false;
		};
	}, [form.site, form.source, debouncedSearch, state.mode, form.lang]);

	const handleOnClick = (item: IStructuredDataContent) => {
		let newSelIds: number[];
		let selItems: IStructuredDataContent[];
		const itemSelectedID = item.dataLanguages?.length
			? item.dataLanguages.find((dataLang) => state.fixed.includes(dataLang.id))?.id
			: state.fixed.includes(item.id)
				? item.id
				: undefined;

		if (itemSelectedID) {
			newSelIds = state.fixed.filter((a) => a !== itemSelectedID);
			selItems = state.selectedItems.filter((b) => b.id !== itemSelectedID);
		} else {
			newSelIds = [...state.fixed, item.id];
			selItems = [...state.selectedItems, item];
		}
		const showSelected = state.showSelected && newSelIds.length === 0 ? false : state.showSelected;
		setState((state) => ({ ...state, fixed: newSelIds, selectedItems: selItems, showSelected }));
	};

	const handleSelectedClick = () => setState((state) => ({ ...state, showSelected: !state.showSelected }));

	const handleAdd = () => {
		const { mode, fixed, fullRelations, site, lang } = state;
		const newValue = { mode, fixed, fullRelations, site, lang };
		onChange(newValue);
		handleValidation?.(state.fixed.join(","), validators);
	};

	const textFieldProps = {
		value: state.search,
		onChange: (search: string) => setState((state) => ({ ...state, search })),
		placeholder: "Search",
		icon: "search",
		iconPosition: "in",
	};

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

	const showedItems = state.showSelected ? state.selectedItems : state.items;

	const options = state.sourceTitles.map((singleSource) => {
		return { label: singleSource.title, value: singleSource.id };
	});

	const handleSource = (newSource: string) => setForm({ ...form, source: newSource });

	const handleLang = (newLang: string) => setForm({ ...form, lang: parseInt(newLang) });

	const handleSite = (newSite: string | number | null) => {
		if (typeof newSite !== "number" && newSite !== null) return;
		setForm({ ...form, site: newSite });
		const siteID = newSite !== currentSite && newSite !== null ? newSite : undefined;
		setState((state) => ({ ...state, site: siteID }));
	};

	return (
		<S.Wrapper>
			{state.fixed.length > 0 && (
				<S.ButtonWrapper>
					<Button type="button" buttonStyle="text" onClick={handleSelectedClick}>
						{buttonText}
					</Button>
				</S.ButtonWrapper>
			)}
			{!state.showSelected && (
				<>
					<S.SelectsWrapper>
						{globalLangs.length > 1 && (
							<Select
								name="selectLang"
								options={langOptions}
								onChange={handleLang}
								value={form.lang.toString()}
								type="inline"
								mandatory={true}
							/>
						)}
						{
							<AsyncSelect
								name="select"
								entity="sites"
								onChange={handleSite}
								value={form.site}
								type="inline"
								placeholder={currentSite ? "Select" : "Global"}
								maxWidth={130}
								mandatory={!!currentSite}
							/>
						}
						{state.sourceTitles.length > 1 && (
							<Select
								name="selectSource"
								options={options}
								onChange={handleSource}
								value={form.source}
								type="inline"
								mandatory={true}
								maxWidth={70}
							/>
						)}
					</S.SelectsWrapper>
					<S.SearchWrapper>
						<TextField {...textFieldProps} />
					</S.SearchWrapper>
				</>
			)}
			{isLoading ? (
				<S.LoadingWrapper>
					<Loader name="circle" />
				</S.LoadingWrapper>
			) : (
				<S.ListWrapper>
					<S.Order>Most recent</S.Order>
					<S.ItemList>
						{showedItems?.map((item) => {
							const isChecked = item.dataLanguages?.length
								? item.dataLanguages.some((dataLang) => state.fixed.includes(dataLang.id))
								: state.fixed.includes(item.id);
							const hasVersionInPageLanguage = item.dataLanguages.find(
								(dataLang) => dataLang.language === lang.id && item.language !== lang.id,
							);
							const isSelectedOtherLanguage = item.dataLanguages.find(
								(dataLang) => state.fixed.includes(dataLang.id) && dataLang.language !== form.lang,
							);
							const source = state.sourceTitles.find((el) => el.id === item.structuredData);
							const disabled =
								(hasMaxItems && !isChecked) ||
								!!hasVersionInPageLanguage ||
								(!!maxItems && state.fixed.length >= maxItems && !isChecked);
							return (
								<React.Fragment key={`${item.content.title}-${item.id}`}>
									{source && (
										<Item
											isChecked={isChecked || !!isSelectedOtherLanguage}
											handleOnClick={handleOnClick}
											item={item}
											source={source}
											disabled={disabled}
											tooltip={hasVersionInPageLanguage ? "Content has version in page language" : ""}
										/>
									)}
								</React.Fragment>
							);
						})}
					</S.ItemList>
				</S.ListWrapper>
			)}
			<S.ActionsWrapper>
				{state.fixed.length > 0 && (
					<Button type="button" onClick={handleAdd}>
						Add
					</Button>
				)}
			</S.ActionsWrapper>
		</S.Wrapper>
	);
};

interface IProps {
	currentSite: number | null;
	onChange: (value: any) => void;
	hasMaxItems: boolean;
	handleValidation?: (value: string, validators?: Record<string, unknown>) => void;
	validators?: Record<string, unknown>;
	lang: { locale: string; id: number };
	globalLangs: ILanguage[];
	maxItems?: number;
}

interface IFormState {
	source: string | undefined;
	lang: number;
	site: number | null;
}

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

export default connect(mapStateToProps)(ManualPanel);
