import React, { useEffect, useState } from "react";

import { selects, structuredData } from "@ax/api";
import { Button, FieldsBehavior, IconAction, SearchField, Select, Tag, Tooltip } from "@ax/components";
import { isReqOk } from "@ax/helpers";
import { useCategoryColors } from "@ax/hooks";
import type { ICheck, IDataSource, IGetStructuredDataParams, ISite, IStructuredData } from "@ax/types";

import type { IFilter, ISource, SiteValue } from "../../Context";

import * as S from "./style";

const AutoItem = (props: IProps) => {
	const {
		source,
		canDelete,
		filter,
		handleDelete,
		addFilter,
		currentSite,
		structuredDataSite,
		filterOperator,
		globalOperator,
		siteID,
	} = props;

	const initState: IState = {
		selected: "",
		options: [],
		isOpen: false,
		isAdvancedOpen: false,
		categories: [],
		selectedCategories: [],
		filteredOptions: [],
	};

	const [state, setState] = useState(initState);

	const catIDs = state.categories.map((cat) => cat.label);
	const { categoryColors } = useCategoryColors(catIDs);

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

	const removeItem = () => handleDelete(source.id);

	const menuOptions = [
		{
			label: "delete",
			icon: "delete",
			action: removeItem,
		},
	];

	const getIsGlobal = (id: string) => {
		const data = structuredDataSite?.find((elem) => elem.id === id);
		return !data?.local;
	};

	const getCategoryContent = async (newValue: string) => {
		const params: IGetStructuredDataParams = {
			dataID: newValue,
			page: 1,
			itemsPerPage: 50,
			pagination: false,
			deleted: false,
			include_draft: false,
			order: "alpha-asc",
			groupingCategories: true,
		};

		const site = getIsGlobal(newValue) ? null : (siteID as number);

		try {
			const result = await structuredData.getDataContents(params, site);
			if (isReqOk(result.status)) {
				setState((prev) => ({
					...prev,
					selected: newValue,
					options: result.data.items,
					filteredOptions: result.data.items,
				}));
			}
		} catch (e) {
			console.log(e);
		}
		return false;
	};

	const getCategories = async (): Promise<boolean> => {
		try {
			const result = await selects.getSelectItems("categories", source.id);
			if (isReqOk(result.status)) {
				const selectedCategories = getFiltersCategories(filter, result.data);
				setState((prev) => ({ ...prev, categories: result.data, selectedCategories }));
				return true;
			}
		} catch (e) {
			console.log(e);
		}
		return false;
	};

	const getFiltersCategories = (filters: IFilter[], categories: ICategory[]) => {
		let filterCategories: ICategory[] = [];
		filters.forEach((filter) => {
			const filterCategory = categories.find((cat) => cat.label === filter.category);
			filterCategories =
				filterCategory && !filterCategories.includes(filterCategory)
					? [...filterCategories, filterCategory]
					: filterCategories;
		});
		return filterCategories;
	};

	const handleSelectOnChange = (newValue: string | null) => {
		if (newValue) {
			getCategoryContent(newValue);
		} else {
			setState((prev) => ({ ...prev, selected: "", options: [], filteredOptions: [] }));
		}
	};

	const find = (options: IOption[], id: number): IOption | undefined => {
		for (const option of options) {
			if (option.id === id) return option;
			const found = find(option.children || [], id);
			if (found) return found;
		}
		return undefined;
	};

	const handleCheckChange = (checkValue: ICheck) => {
		if (checkValue.isChecked) {
			const newFilter = find(state.options, checkValue.value);
			if (newFilter) {
				const filterCategory = state.categories.find((cat) => cat.value === newFilter.structuredData);

				setState((prev) => ({
					...prev,
					selectedCategories:
						filterCategory && !prev.selectedCategories.includes(filterCategory)
							? [...prev.selectedCategories, filterCategory]
							: prev.selectedCategories,
				}));

				const updatedSource: ISource = {
					structuredData: source.id,
					filters: [
						...filter,
						{
							id: newFilter.id,
							label: newFilter.content.title,
							category: filterCategory?.label || "",
							color: categoryColors[filterCategory?.label || ""],
						},
					],
					globalOperator: globalOperator,
					filterOperator: filterOperator,
				};

				addFilter(updatedSource);
			}
		} else {
			const newFilters = filter.filter((e) => e.id !== checkValue.value);
			const selectedCategories = getFiltersCategories(newFilters, state.categories);
			setState((prev) => ({ ...prev, selectedCategories }));

			const updatedSource: ISource = {
				structuredData: source.id,
				filters: newFilters,
				globalOperator: globalOperator,
				filterOperator: filterOperator,
			};

			addFilter(updatedSource);
		}
	};

	const isChecked = (id: number) => {
		const ids = filter.map((a) => a.id);
		return ids.includes(id);
	};

	const toggleFilters = () => setState((prev) => ({ ...prev, isOpen: !prev.isOpen }));

	const toggleAdvanced = () => setState((prev) => ({ ...prev, isAdvancedOpen: !prev.isAdvancedOpen }));

	const handleDeleteTag = (id: number) => {
		const newFilters = filter.filter((e) => e.id !== id);
		const selectedCategories = getFiltersCategories(newFilters, state.categories);
		setState((prev) => ({ ...prev, selectedCategories }));
		const updatedSource: ISource = {
			structuredData: source.id,
			filters: newFilters,
			globalOperator: globalOperator,
			filterOperator: filterOperator,
		};
		addFilter(updatedSource);
	};

	const handleFilterOperator = (value: string) => {
		const updatedSource: ISource = {
			structuredData: source.id,
			filters: filter,
			globalOperator: globalOperator,
			filterOperator: value,
		};
		addFilter(updatedSource);
	};

	const handleGlobalOperator = (value: string) => {
		const updatedSource: ISource = {
			structuredData: source.id,
			filters: filter,
			globalOperator: value,
			filterOperator: filterOperator,
		};
		addFilter(updatedSource);
	};

	const filterOptions = (options: IOption[], query: string): IOption[] => {
		const lowerQuery = query.toLowerCase();
		const result: IOption[] = [];
		for (const option of options) {
			if (option.content.title.toLowerCase().includes(lowerQuery)) {
				result.push(option);
			}
			const children = filterOptions(option.children || [], query);
			result.push(...children);
		}
		return result;
	};

	const handleSearchChange = (query: string) => {
		setState((prev) => {
			const filteredOptions = query.trim() !== "" ? filterOptions(prev.options, query) : prev.options;
			return { ...prev, filteredOptions };
		});
	};

	const handleClearFilters = () => {
		setState((prev) => ({ ...prev, selectedCategories: [] }));
		const updatedSource: ISource = {
			structuredData: source.id,
			filters: [],
		};
		addFilter(updatedSource);
	};

	const operatorOptions = [
		{ value: "OR", label: "OR" },
		{ value: "AND", label: "AND" },
	];

	const renderChecks = (options: IOption[]) => {
		return options.map((item) => {
			return (
				<React.Fragment key={item.id}>
					{item.type === "group" ? (
						<S.GroupTitle>{item.content.title}</S.GroupTitle>
					) : (
						<S.StyledCheckField
							key={item.id}
							title={item.content.title}
							name={item.id}
							value={item.id}
							checked={isChecked(item.id)}
							onChange={handleCheckChange}
						/>
					)}
					{item.children && <S.GroupWrapper>{renderChecks(item.children)}</S.GroupWrapper>}
				</React.Fragment>
			);
		});
	};

	return (
		<S.TypeContainer key={source.id}>
			<S.TypeWrapper data-testid="item-type-wrapper">
				<S.TypeLabel>Type</S.TypeLabel>
				<S.TypeName>{source.title}</S.TypeName>
				<S.ActionsWrapper>
					<S.IconWrapper>
						<Tooltip content="Filters">
							<IconAction icon="filter" onClick={toggleFilters} active={state.isOpen} />
						</Tooltip>
					</S.IconWrapper>
					<S.IconWrapper>
						<Tooltip content="Advanced settings">
							<IconAction icon="settings" onClick={toggleAdvanced} active={state.isAdvancedOpen} />
						</Tooltip>
					</S.IconWrapper>
					{canDelete && <S.StyledActionMenu icon="more" options={menuOptions} tooltip="Options" />}
				</S.ActionsWrapper>
			</S.TypeWrapper>
			<S.FiltersWrapper isActive={state.isAdvancedOpen} isEmpty={filter.length === 0}>
				{filter?.map((e) => {
					const handleClick = () => handleDeleteTag(e.id);
					const filterName = e.category ? `${e.category}: ${e.label}` : e.label;
					return (
						<Tag
							key={e.label}
							text={filterName}
							onDeleteAction={handleClick}
							color={e.color || categoryColors[e.category || ""]}
						/>
					);
				})}
				{state.isAdvancedOpen && (
					<S.OptionsBlock>
						Relation between filters{" "}
						<S.SelectWrapper>
							<Select
								name="filterOperator"
								options={operatorOptions}
								onChange={handleFilterOperator}
								value={filterOperator || "OR"}
								type="inline"
								mandatory={true}
							/>
						</S.SelectWrapper>
					</S.OptionsBlock>
				)}
			</S.FiltersWrapper>
			{state.isAdvancedOpen && (
				<S.FiltersWrapper isActive={state.isAdvancedOpen} isEmpty={state.selectedCategories.length === 0}>
					{state.selectedCategories.map((e) => {
						return <Tag key={e.label} text={e.label} color={categoryColors[e.label]} rounded={false} />;
					})}
					<S.OptionsBlock>
						Relation between categories{" "}
						<S.SelectWrapper>
							<Select
								name="globalOperator"
								options={operatorOptions}
								onChange={handleGlobalOperator}
								value={globalOperator || "AND"}
								type="inline"
								mandatory={true}
							/>
						</S.SelectWrapper>
					</S.OptionsBlock>
				</S.FiltersWrapper>
			)}
			{filter.length > 0 && (
				<S.ClearWrapper>
					<Button type="button" buttonStyle="minimal" onClick={handleClearFilters}>
						Clear All Filters
					</Button>
				</S.ClearWrapper>
			)}
			<S.ActionsFilterWrapper isOpen={state.isOpen}>
				<FieldsBehavior
					title="Create filter by"
					name="categorySelect"
					fieldType="Select"
					value={state.selected}
					onChange={handleSelectOnChange}
					options={state.categories}
					placeholder="Select..."
					entityId={source.id}
					site={currentSite}
				/>
				{state.options.length > 0 && (
					<S.SearchWrapper>
						<SearchField onChange={handleSearchChange} searchOnEnter={false} size="XS" />
					</S.SearchWrapper>
				)}
				<S.ChecksWrapper>{state.filteredOptions && renderChecks(state.filteredOptions)}</S.ChecksWrapper>
			</S.ActionsFilterWrapper>
		</S.TypeContainer>
	);
};

interface IState {
	selected: string;
	options: IOption[];
	isOpen: boolean;
	isAdvancedOpen: boolean;
	categories: ICategory[];
	selectedCategories: ICategory[];
	filteredOptions: IOption[];
}

interface ICategory {
	value: string;
	label: string;
}

interface IOption {
	id: number;
	content: { title: string; code: string };
	dataLanguages?: { id: number; language: number }[];
	type: "category" | "group";
	children?: IOption[];
	selectable?: boolean;
	structuredData: string;
}

interface IProps {
	source: IDataSource;
	canDelete: boolean;
	filter: IFilter[];
	currentSite: ISite | null;
	structuredDataSite: IStructuredData[];
	filterOperator?: string;
	globalOperator?: string;
	handleDelete: (value: string) => void;
	addFilter: (source: ISource) => void;
	siteID?: SiteValue | null;
}

export default AutoItem;
