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

import { useModal } from "@ax/hooks";
import type { IDataSource, ISite, IRootState, IStructuredData } from "@ax/types";
import { structuredData } from "@ax/api";
import { capitalize, isReqOk, splitCamelCase } from "@ax/helpers";
import { IconAction, FloatingPanel, Select, Tag, Icon } from "@ax/components";

import AutoPanel from "./AutoPanel";
import ItemList from "./ItemList";
import ManualPanel from "./ManualPanel";
import {
	useReference,
	ReferenceProvider,
	type ISource,
	type IRefField,
	type ReferenceMode,
	type OrderDirection,
} from "./Context";

import * as S from "./style";

const ReferenceFieldWithProvider = (props: IReferenceFieldProps) => (
	<ReferenceProvider modes={props.selectionType}>
		<ReferenceField {...props} />
	</ReferenceProvider>
);

const ReferenceField = (props: IReferenceFieldProps) => {
	const {
		sources,
		value,
		onChange,
		disabled,
		site,
		selectionType,
		structuredDataValues,
		categories,
		validators,
		maxItems,
		resetValidation,
		handleValidation,
		mandatory,
		editorID,
	} = props;

	const { isOpen, toggleModal } = useModal();

	const { state, setState, setModeAndSource } = useReference();
	const { mode } = state;
	const singleMode = selectionType && selectionType.length === 1;
	const isAuto = mode === "auto";
	const hasMaxItems = !!(value?.fixed && maxItems && !isAuto && value.fixed.length >= maxItems);
	const sourcesIDs = sources.map((source) => source.structuredData);
	const { fixed, order, quantity, allLanguages, preferenceLanguage, fullRelations = false } = state;

	const handleMode = (mode: ReferenceMode) => {
		const manualSources: string[] = [...new Set<string>(state.selectedItems.map((selItem) => selItem.structuredData))];

		const resetSource = mode === "manual" || sourcesIDs.length === 1 ? sourcesIDs : manualSources;
		const mappedSources = resetSource.map((source) => {
			return { structuredData: source, filters: [], filterOperator: "OR", globalOperator: "AND" };
		});

		const newValue =
			mode === "auto"
				? {
						mode,
						sources: mappedSources,
						order,
						quantity,
						fullRelations,
						allLanguages,
						preferenceLanguage,
					}
				: {
						mode,
						fixed,
						fullRelations,
					};
		onChange(newValue);
		setModeAndSource(mode, mappedSources);
		resetValidation?.();
	};

	// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
	useEffect(() => {
		const getSourcesTitles = async () => {
			const response = await structuredData.getDataTitles(sourcesIDs);
			if (isReqOk(response?.status)) {
				return response.data;
			} else {
				console.error("Error en getSourcesTitles");
				return [];
			}
		};

		let isMounted = true;
		getSourcesTitles().then((result: IDataSource[]) => {
			if (!isMounted) return;
			setState((prev) => {
				let sources = value?.sources;
				if (prev.mode === "auto" && !sources && sourcesIDs[0]) {
					sources = [{ structuredData: sourcesIDs[0], filters: [], filterOperator: "OR", globalOperator: "AND" }];
				}
				let newState = { ...prev, ...value, sourceTitles: result, sources: sources || [] };
				if (value?.order) {
					const [order, orderDirection = "ASC"] = value.order.split("-");
					newState = { ...newState, order, orderDirection: orderDirection as OrderDirection };
				}
				return newState;
			});
		});

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

	const handleAddItems = () => {
		setState((state) => ({ ...state, showSelected: false }));
		toggleModal();
	};

	const options = [
		{ label: "Manual", value: "manual" },
		{ label: "Automatic", value: "auto" },
	];

	const handleOnChange = (newValue: IRefField) => {
		onChange(newValue);
		toggleModal();
	};

	const handleListDelete = (fixed: number[]) => {
		const newValue = {
			mode,
			fixed,
			fullRelations,
		};
		onChange(newValue);
		resetValidation?.();
	};

	const handleListMove = (fixed: number[]) => {
		const newValue = {
			mode,
			fixed,
			fullRelations,
		};
		onChange(newValue);
	};

	const icon = isAuto ? "edit" : "add";

	const defaultOrders: Record<string, string> = {
		alpha: "Alphabetical order",
		recent: "Most recent",
	};

	const getOrderLabel = () => {
		const stateOrder = splitCamelCase(state.order).toLowerCase();
		const orderLabel = defaultOrders[state.order] || capitalize(stateOrder);
		const directionLabel = state.orderDirection === "ASC" ? "(ascendent)" : "(descendent)";
		return `${orderLabel} ${directionLabel}`;
	};

	const renderAutoData = () => (
		<S.DataWrapper data-testid="auto-data-wrapper">
			<S.SourcesWrapper>
				{value?.sources?.map((singleSource) => {
					const srcTitle = state.sourceTitles.find((source) => source.id === singleSource.structuredData);
					return (
						<S.TypeContainer key={singleSource.structuredData}>
							<S.Title>{srcTitle?.title}</S.Title>
							<div>
								{singleSource.filters?.map((f) => (
									<Tag key={f.label} text={f.category ? `${f.category}: ${f.label}` : f.label} color={f.color} />
								))}
							</div>
						</S.TypeContainer>
					);
				})}
			</S.SourcesWrapper>
			<S.ConfigWrapper>
				{value?.quantity ? `${value.quantity} items` : "All items"} - {getOrderLabel()}
			</S.ConfigWrapper>
		</S.DataWrapper>
	);

	const getPanel = () =>
		isAuto ? (
			<AutoPanel
				structuredData={structuredDataValues}
				categories={categories}
				onChange={handleOnChange}
				site={site}
				validators={validators}
			/>
		) : (
			<ManualPanel
				onChange={handleOnChange}
				hasMaxItems={hasMaxItems}
				handleValidation={handleValidation}
				validators={validators}
				maxItems={maxItems}
			/>
		);

	const manualItems = !isAuto && value && Array.isArray(value.fixed) ? value.fixed.length : 0;

	const dataBlock = isAuto ? (
		renderAutoData()
	) : (
		<ItemList
			items={value?.fixed ? value.fixed : []}
			handleListDelete={handleListDelete}
			handleListMove={handleListMove}
			site={value?.site}
		/>
	);

	return (
		<S.Wrapper data-testid="reference-field-wrapper">
			<S.Label>
				Elements
				{mandatory && <S.Asterisk>*</S.Asterisk>}
			</S.Label>
			<S.Note>
				Only <strong>published</strong> &#40; <Icon name="active" size="16" /> &#41; data is displayed. &apos;Pending to
				publish&apos; &#40; <Icon name="uploadPending" size="16" /> &#41; data won&apos;t appear until the publishing
				process is complete.
			</S.Note>
			<S.ModeWrapper>
				{!singleMode && (
					<Select
						name="select"
						options={options}
						onChange={(value: string) => handleMode(value as ReferenceMode)}
						value={mode}
						type="inline"
						disabled={disabled}
						mandatory={true}
					/>
				)}
				{singleMode && !isAuto && value && <S.SingleModeText>{manualItems} items</S.SingleModeText>}
				{singleMode && isAuto && <S.SingleModeText>Configure automatic selection</S.SingleModeText>}
				{!disabled && !hasMaxItems && (
					<S.ActionWrapper>
						<IconAction icon={icon} onClick={handleAddItems} />
					</S.ActionWrapper>
				)}
			</S.ModeWrapper>
			{dataBlock}
			<FloatingPanel title="Configure elements" toggleModal={toggleModal} isOpen={isOpen}>
				{isOpen && getPanel()}
			</FloatingPanel>
		</S.Wrapper>
	);
};

export interface IReferenceFieldProps {
	sources: ISource[];
	value?: IRefField;
	onChange: (value: IRefField) => void;
	disabled?: boolean;
	site: ISite | null;
	selectionType?: ReferenceMode[];
	structuredDataValues: { global: IStructuredData[]; site: IStructuredData[] };
	categories: { global: IStructuredData[]; site: IStructuredData[] };
	validators?: Record<string, unknown>;
	maxItems?: number;
	resetValidation?: () => void;
	handleValidation?: (value: string, validators?: Record<string, unknown>) => void;
	mandatory: boolean;
	editorID: number;
}

const mapStateToProps = (state: IRootState) => ({
	structuredDataValues: state.structuredData.structuredData,
	categories: state.structuredData.categories,
});

export default connect(mapStateToProps, null)(ReferenceFieldWithProvider);
