/**
 * 
 * @since 2.5.3
 */

const { components } = window.wp;
const { createElement, useMemo, useState, useEffect } = wp.element || {};
const { SelectControl, Button, DateTimePicker, Spinner, TextareaControl } = wp.components || {};
const { MediaUpload, MediaUploadCheck } = wp.blockEditor || {};
const ToggleGroupControl = (components && components.__experimentalToggleGroupControl) || {};
const ToggleGroupControlOption = (components && components.__experimentalToggleGroupControlOption) || {};
const { __, _x } = wp.i18n || {};
const apiFetch = wp.apiFetch || {};

// Convertir camelCase en texte lisible
export const camelCaseToLabel = (str) => {
	return str
		.replace(/([A-Z])/g, ' $1') // Ajoute un espace avant les majuscules
		.replace(/^./, (char) => char.toUpperCase()) // Majuscule au début
		.trim();
};

/**
 * Nettoie les valeurs des champs texte avant sauvegarde
 * @param {any} value - Valeur brute du champ
 * @param {object} field - Objet champ contenant acf_type
 * @returns {any} Valeur nettoyée
 */
export const eacSanitizeFieldValue = (value, field) => {
	if (value === null || value === undefined) {
		return value;
	}

	switch (field.acf_type) {
		// ========== TEXT ==========
		case 'text': {
			return String(value)
				.trim()                         // Espaces début/fin
				.replace(/\s+/g, ' ')           // Espaces multiples → 1 espace
				.replace(/<[^>]*>/g, '')        // Supprimer tags HTML
				.substring(0, 255);             // Limiter à 255 caractères
		}

		// ========== URL ==========
		case 'url': {
			const url = String(value).trim();

			// Rejeter protocoles dangereux
			if (/^(javascript|data|vbscript):/i.test(url)) {
				return '';
			}

			// Valider format basique
			if (url && !/^(https?:\/\/|mailto:|\/|\.\/|#)/i.test(url)) {
				return '';
			}

			// Supprimer tags HTML si présents
			return url.replace(/<[^>]*>/g, '');
		}

		// ========== TEXTAREA ==========
		case 'textarea': {
			return String(value)
				.trim()
				.replace(/<script[^>]*>.*?<\/script>/gi, '')     // Supprimer scripts
				.replace(/<iframe[^>]*>.*?<\/iframe>/gi, '')     // Supprimer iframes
				.replace(/on\w+\s*=\s*["'][^"']*["']/gi, '')     // Supprimer event handlers
				.substring(0, 1000);                             // Limiter à 1000 caractères
		}

		// ========== AUTRES (select, date, page_link, button_group) ==========
		// Nettoyage basique, la vraie validation se fait côté PHP
		default: {
			return String(value).trim().replace(/<[^>]*>/g, '');
		}
	}
};

export const renderImagePanel = ({ fieldKey, field, attributes, handleChange }) => {
	const value = attributes[field.name] || '';
	const getImageUrl = (image) => {
		if (!image) {
			return '';
		}
		return typeof image === 'object'
			? image.url || image.src || image.source_url || ''
			: image;
	};

	const getCurrentImageUrl = () => getImageUrl(value || attributes[field.name] || '');
	const selectedImageId = (typeof attributes[field.name] === 'object' && attributes[field.name] && attributes[field.name].id) ? attributes[field.name].id : 0;

	// États
	const [selectedValue, setSelectedValue] = useState(getCurrentImageUrl());
	const [mediaId, setMediaId] = useState(selectedImageId);
	const [isLoading, setIsLoading] = useState(false);

	// Fonction pour générer srcset
	const generateSrcset = (media) => {
		const sizes = media.media_details?.sizes;
		if (!sizes || typeof sizes !== 'object') {
			return media.source_url;
		}

		const srcsetArray = [];
		Object.keys(sizes).forEach((sizeKey) => {
			const sizeObj = sizes[sizeKey];
			if (sizeObj.source_url && sizeObj.width) {
				srcsetArray.push(sizeObj.source_url.concat(' ').concat(sizeObj.width).concat('w'));
			}
		});

		// Ajouter l'image full si elle n'est pas déjà incluse
		if (media.source_url && media.media_details?.width) {
			const fullSrcset = media.source_url.concat(' ').concat(media.media_details.width).concat('w');
			if (!srcsetArray.includes(fullSrcset)) {
				srcsetArray.push(fullSrcset);
			}
		}

		return srcsetArray.length > 0 ? srcsetArray.join(', ') : media.source_url;
	};

	// Fonction pour générer sizes
	const generateSizes = (media) => {
		const mediumSize = media.media_details?.sizes?.medium;
		if (!mediumSize || !mediumSize.width) {
			return 'auto';
		}

		const width = mediumSize.width;
		return 'auto, (max-width: '.concat(width).concat('px) 100vw, ').concat(width).concat('px');
	};

	// Récupération des données via API REST
	useEffect(() => {
		let isMounted = true;

		if (!mediaId || mediaId === 0) {
			setSelectedValue('');
			return;
		}

		setIsLoading(true);

		const apiPath = '/wp/v2/media/'.concat(mediaId);

		apiFetch({ path: apiPath })
			.then((media) => {
				if (!isMounted) return;
				const imageDataArray = {
					id: media.id,
					src: media.source_url || '',
					srcset: generateSrcset(media),
					sizes: generateSizes(media),
					width: media.media_details?.width || 0,
					height: media.media_details?.height || 0,
					alt: media.alt_text || '',
					title: media.title?.rendered || media.title || '',
				};

				setSelectedValue(imageDataArray.src);
				handleChange(field.name, imageDataArray);
				setIsLoading(false);
			})
			.catch((error) => {
				if (!isMounted) return;
				console.error('Erreur récupération image:', error);
				setIsLoading(false);
			});

		// Cleanup function - démontage du composant
		return () => {
			isMounted = false;
		};
	}, [mediaId]);

	const onRemoveImage = () => {
		setSelectedValue('');
		setMediaId(0);
		handleChange(field.name, '');
	};

	const imageUrl = selectedValue || getCurrentImageUrl();

	return createElement('div', { className: 'eac-image-control', style: { marginBlockEnd: '16px' } },
		createElement(MediaUploadCheck, null,
			createElement(MediaUpload, {
				key: fieldKey,
				onSelect: (media) => {
					setMediaId(media.id);
				},
				allowedTypes: ['image'],
				value: mediaId,
				render: ({ open }) => createElement('div',
					{
						style: {
							backgroundImage: imageUrl ? 'url("' + imageUrl + '")' : 'none',
							backgroundSize: 'cover',
							backgroundPosition: 'center',
							minHeight: '120px',
							border: '2px dashed #ccc',
							display: 'flex',
							alignItems: 'center',
							justifyContent: 'center',
							opacity: isLoading ? 0.6 : 1,
							transition: 'opacity 0.2s',
						}
					},
					createElement('div', null,
						createElement(Button, { onClick: open, variant: 'primary', disabled: isLoading },
							isLoading ? __('Loading...', 'eac-components') : imageUrl ? __('Change', 'eac-components') : __('Add image', 'eac-components')
						),
						imageUrl && !isLoading
							? createElement(Button, { onClick: onRemoveImage, variant: 'secondary' }, __('Remove', 'eac-components'))
							: null
					)
				),
				help: field.instructions || '',
			})
		)
	);
};

export const renderPageLinkControl = ({ fieldKey, field, attributes, handleChange }) => {
	const [selectedValue, setSelectedValue] = useState(attributes[field.name] || '');
	const [postsData, setPostsData] = useState({});
	const [isLoading, setIsLoading] = useState(true);

	// Préparer les post_types
	const postTypes = Array.isArray(field.post_type) ? field.post_type : [];

	useEffect(() => {
		setSelectedValue(attributes[field.name] || '');
	}, [attributes[field.name]]);

	useEffect(() => {
		let mounted = true;
		setIsLoading(true);

		// Convertir postTypes (array ou string) en string pour les paramètres
		let postTypesStr = '';
		if (Array.isArray(postTypes)) {
			postTypesStr = postTypes.join(',');
		} else if (typeof postTypes === 'string') {
			postTypesStr = postTypes;
		}

		// Construire les paramètres
		const params = new URLSearchParams();
		if (postTypesStr) {
			params.append('post_types', postTypesStr);
		}

		const endpoint = `/eac-blocks/v1/post-types${params.toString() ? '?' + params.toString() : ''}`;

		apiFetch({
			path: endpoint,
			method: 'GET',
			headers: { 'Accept': 'application/json' }
		})
			.then(result => {
				if (!mounted) return;
				const posts = result && typeof result === 'object' ? result : {};
				setPostsData(posts);
			})
			.catch((error) => {
				if (!mounted) return;
				console.error('Erreur lors du chargement des posts:', error);
				setPostsData({});
			})
			.finally(() => {
				if (!mounted) return;
				setIsLoading(false);
			});

		return () => { mounted = false; };
	}, []);

	const commonProps = {
		key: fieldKey,
		label: field.label ? field.label : field.name,
	};

	// Construire les optgroups
	const optgroupElements = useMemo(() => {
		return Object.entries(postsData).map(([slug, data]) => {
			const items = data.items || [];
			const label = data.label || slug;

			if (items.length === 0) {
				return null;
			}

			return createElement(
				'optgroup',
				{ key: slug, label: label },
				items.map((item) => {
					return createElement(
						'option',
						{ key: item.link, value: item.link },
						item.title
					);
				})
			);
		}).filter(Boolean);
	}, [postsData]);

	if (isLoading) {
		return createElement(Spinner);
	}

	return createElement(SelectControl, {
		...commonProps,
		value: selectedValue,
		__next40pxDefaultSize: true,
		__nextHasNoMarginBottom: true,
		children: [
			createElement('option', { key: 'empty', value: '' }, __('Select...', 'eac-components')),
			...optgroupElements
		],
		onChange: (value) => {
			setSelectedValue(value);
			handleChange(field.name, value);
		},
		help: field.instructions || '',
	});
};

export const renderDateTimePickerControl = ({ fieldKey, field, attributes, handleChange }) => {
	const [selectedValue, setSelectedValue] = useState(attributes[field.name] || '');
	const [isOpen, setIsOpen] = useState(false);

	useEffect(() => {
		setSelectedValue(attributes[field.name] || '');
	}, [attributes, field.name]);

	const pad = (num) => String(num).padStart(2, '0');

	const formatIso = (date) => {
		return date.getFullYear() + '-' + pad(date.getMonth() + 1) + '-' + pad(date.getDate()) + 'T' + pad(date.getHours()) + ':' + pad(date.getMinutes());
	};

	// Fonction pour formater selon le display_format d'ACF
	const formatWithAcfFormat = (dateString, format, locale = 'fr-FR') => {
		if (!dateString) return '';
		const date = dateString instanceof Date ? dateString : new Date(dateString.replace('T', ' '));
		const hours24 = date.getHours();
		const hours12 = hours24 % 12 || 12;

		// Récupère les jours avec Intl (natif, toutes les langues)
		const dayShort = new Intl.DateTimeFormat(locale, { weekday: 'short' }).format(date);
		const dayLong = new Intl.DateTimeFormat(locale, { weekday: 'long' }).format(date);

		const replacements = {
			'D': dayShort,                      // ← Jour abrégé (Mon, lun, etc)
			'l': dayLong,                       // ← Jour complet (Monday, lundi, etc)
			'd': pad(date.getDate()),
			'm': pad(date.getMonth() + 1),
			'Y': date.getFullYear(),
			'y': String(date.getFullYear()).slice(-2),
			'g': hours12,
			'G': hours24,
			'H': pad(hours24),
			'h': pad(hours12),
			'i': pad(date.getMinutes()),
			's': pad(date.getSeconds()),
			'a': hours24 >= 12 ? 'pm' : 'am',
			'A': hours24 >= 12 ? 'PM' : 'AM',
		};

		return format.replace(/D|l|d|m|Y|y|H|h|g|G|i|s|a|A/g, (match) => replacements[match]);
	};

	const currentValue = selectedValue || formatIso(new Date());
	const timeFormat = field.picker === '12' ? '12' : '24';
	const label = field.label || field.name;

	// Appliquer le display_format au texte du bouton
	const displayFormat = field.display_format;
	const buttonText = selectedValue
		? formatWithAcfFormat(selectedValue, displayFormat)
		: label;

	return createElement('div', { key: fieldKey, className: 'eac-date-time-picker-control' },
		createElement(Button, {
			style: { marginBlockEnd: '16px' },
			isSecondary: true,
			onClick: () => setIsOpen(!isOpen),
			__next40pxDefaultSize: true,
		}, buttonText),
		isOpen ? createElement(DateTimePicker, {
			currentDate: currentValue,
			is12Hour: timeFormat === '12',
			onChange: (value) => {
				setSelectedValue(value);
				handleChange(field.name, value);
				setIsOpen(false);
			},
			__next40pxDefaultSize: true,
			help: field.instructions || '',
		}) : null
	);
};

export const renderButtonGroup = ({ fieldKey, field, attributes, handleChange }) => {
	const commonProps = {
		key: fieldKey,
		label: field.label ? field.label : camelCaseToLabel(field.name),
		value: attributes[field.name] ?? field.default ?? '',
		onChange: (value) => handleChange(field.name, value)
	};
	const renderChoicesOptions = (field.choices || []).map(({ label, value }) => createElement(
		ToggleGroupControlOption,
		{
			label: label,
			value: value
		}
	));

	return createElement(ToggleGroupControl, {
		...commonProps,
		__next40pxDefaultSize: true,
		isBlock: true,
		isAdaptativeWidth: false,
		help: field.instructions || '',
	}, ...renderChoicesOptions);
};

export const renderTextareaControl = ({ fieldKey, field, attributes, handleChange }) => {
	const [value, setValue] = useState(attributes[field.name]);

	// Important le control peut être utiliser plusieurs fois par différents champs, donc on doit écouter le changement de fieldKey et de attributes[field.name]
	useEffect(() => {
		setValue(attributes[field.name]);
	}, [fieldKey, attributes[field.name]]);

	return createElement(TextareaControl, {
		key: fieldKey,
		label: field.label ? field.label : camelCaseToLabel(field.name),
		value: value,
		onChange: (tac) => setValue(tac),  // ← Changement local uniquement
		onBlur: () => {
			const cleanedValue = eacSanitizeFieldValue(value, field);
			handleChange(field.name, cleanedValue);
		},
		__next40pxDefaultSize: true,
		__nextHasNoMarginBottom: true,
		placeholder: field.placeholder || '',
		rows: field.rows || 4,
		help: field.instructions ? field.instructions : __('Type your content and click outside to preview', 'eac-components'),
	});
};