( function( blocks, element, blockEditor, components ) {
	'use strict';

	var el = element.createElement;
	const { registerBlockType } = blocks;
	const { InspectorControls, useBlockProps } = blockEditor;
	const { PanelBody, SelectControl, ColorPalette, ToggleControl, RangeControl, Placeholder } = components;

	const iconSvg ="M6.2,2.6H2.7v3.5h3.5V2.6z M5,5H3.9V3.8H5V5z M13.2,2.6H9.7v3.5h3.5V2.6z M12,5h-1.2V3.8H12V5z M6.2,9.7H2.7v3.5h3.5V9.7z M5,12H3.9v-1.2H5V12z M15.2,0H0v15.2L4.8,20H20V4.9L15.2,0z M7.3,14.3H1.5V8.5h5.8V14.3z M7.3,7.3H1.5V1.4h5.8V7.3z M14.3,12h-1.2 v1.2h1.2v1.2h-1.2v-1.2H12v1.2h-1.2v-1.2H9.7v1.2H8.5v-1.2h1.2V12H8.5V8.5h1.2v1.2h1.2v3.5H12V9.7h1.2V8.5h1.2V12z M14.3,7.3H8.5 V1.4h5.8V7.3z";
	const iconEl = el('svg', { width: 20, height: 20, fill: '#555d66' }, el('path', { d: iconSvg }));
	const dragHandleIcon = el('svg', { width: 16, height: 16, viewBox: '0 0 24 24', fill: 'currentColor', className: 'qrcdr-drag-handle-icon' },
		el('path', { d: 'M3 15h18v-2H3v2zm0 4h18v-2H3v2zm0-8h18V9H3v2zm0-6v2h18V6H3z' })
	);

	const selectSidebar = [ { label: 'Left', value: 'left' }, { label: 'Right', value: 'right' } ];

	// Queste sono solo per l'inizializzazione, l'ordine effettivo sarà gestito dalla logica useEffect
	const initialTabs = Object.keys(QRCDRblock.tabs).map(key => ({ 
		id: key, 
		label: QRCDRblock.tabs[key].label, 
		className: QRCDRblock.tabs[key].className || '', 
		enabled: key === 'link', // Attiva solo il tab 'link' di default
	}));
	const initialFeatures = Object.keys(QRCDRblock.features).map(key => ({ 
		id: key, 
		label: QRCDRblock.features[key].label, 
		className: QRCDRblock.features[key].className || '', 
		enabled: key === 'colors', // Attiva solo il tab 'link' di default
	}));

	registerBlockType( 'qrcdr/qrcdr-block', {
		icon: iconEl,
		attributes: {
			qrcdr_sidebar: { type: 'string', default: 'right' },
			// L'inizializzazione qui non è critica quanto la logica in useEffect
			qrcdr_tabs: { type: 'array', default: initialTabs },
			qrcdr_features: { type: 'array', default: initialFeatures },
			qrcdr_color: {
				type: 'string',
				// default: QRCDRblock.main_color
			},
			qrcdr_collapse: { type: 'boolean', default: false },
			qrcdr_single: { type: 'boolean', default: false },
			qrcdr_border_radius_value: {
				type: 'number',
				// default: parseInt(QRCDRblock.border_radius, 10) || 0 
			},
			qrcdr_text_field: { type: 'string', default: '' },
		},

		edit: function( props ) {
			const blockProps = useBlockProps();
			const { attributes, setAttributes } = props;

			element.useEffect(() => {
				const availableTabs = QRCDRblock.tabs;
				const availableFeatures = QRCDRblock.features;
				const savedTabs = attributes.qrcdr_tabs;
				const savedFeatures = attributes.qrcdr_features;

				// Funzione helper per sincronizzare le liste mantenendo l'ordine salvato
				const synchronizeList = (savedItems, availableItems) => {
					// Se savedItems non è un array, crea un array vuoto per evitare errori
					const currentSavedItems = Array.isArray(savedItems) ? savedItems : [];
					const savedItemsMap = new Map(currentSavedItems.map(item => [item.id, item]));
					const synchronizedList = [];

					// 1. Aggiungi gli elementi salvati nell'ordine salvato
					currentSavedItems.forEach(savedItem => {
						if (availableItems.hasOwnProperty(savedItem.id)) {
							synchronizedList.push({
								id: savedItem.id,
								label: availableItems[savedItem.id].label,
								className: availableItems[savedItem.id].className || '',
								enabled: savedItem.enabled // Mantiene lo stato 'enabled' salvato
							});
						}
					});

					// 2. Aggiungi eventuali nuovi elementi disponibili che non erano salvati
					Object.keys(availableItems).forEach(key => {
						if (!savedItemsMap.has(key)) {
							synchronizedList.push({
								id: key,
								label: availableItems[key].label,
								className: availableItems[key].className || '',
								enabled: false // Nuovo elemento, di default disabilitato
							});
						}
					});
					return synchronizedList;
				};

				const synchronizedTabs = synchronizeList(savedTabs, availableTabs);
				const synchronizedFeatures = synchronizeList(savedFeatures, availableFeatures);

				// Aggiorna gli attributi solo se c'è stato un cambiamento effettivo (inclusi nuovi elementi o cambiamenti di ordine)
				if (JSON.stringify(savedTabs) !== JSON.stringify(synchronizedTabs)) {
					setAttributes({ qrcdr_tabs: synchronizedTabs });
				}
				if (JSON.stringify(savedFeatures) !== JSON.stringify(synchronizedFeatures)) {
					setAttributes({ qrcdr_features: synchronizedFeatures });
				}

			}, [attributes.qrcdr_tabs, attributes.qrcdr_features]); // Aggiungi gli attributi alle dipendenze per assicurare la re-esecuzione quando cambiano.

			const { qrcdr_sidebar, qrcdr_tabs, qrcdr_color, qrcdr_collapse, qrcdr_single, qrcdr_features, qrcdr_border_radius_value, qrcdr_text_field } = attributes;

			let draggedItemIndex = null;
			let dragContainer = null;

			let dragGhost = null; // Elemento fantasma per il touch
			let initialTouchY = 0; // Posizione Y iniziale del touch (non usata direttamente ma utile per debugging o logica più complessa)
			let currentTouchElement = null; // Elemento sotto il touch corrente
			let initialGhostOffsetX = 0; // Store initial touch offset for consistent drag
			let initialGhostOffsetY = 0;

			const reorderArray = (list, startIndex, endIndex) => {
				const result = Array.from(list);
				const [removed] = result.splice(startIndex, 1);
				// Calcolo corretto per inserire l'elemento nella nuova posizione
				const finalIndex = startIndex < endIndex ? endIndex : endIndex; // L'indice finale è quello della destinazione
				result.splice(finalIndex, 0, removed);
				return result;
			};

			const startDrag = (event, index, originalElement) => {
				draggedItemIndex = index;

				dragContainer = originalElement.closest('.qrcdr-sortable-container');
				if (dragContainer) {
					dragContainer.classList.add('is-dragging-active');
				}

				originalElement.classList.add('is-dragging');

				// Crea e gestisci il nostro custom dragGhost SOLO per eventi touch
				if (event.touches && event.touches.length > 0) {
					const clone = originalElement.cloneNode(true);
					clone.classList.add('qrcdr-drag-ghost');
					document.body.appendChild(clone);
					dragGhost = clone;
					const rect = originalElement.getBoundingClientRect();
					const touch = event.touches[0];

					// Calcola l'offset iniziale dal punto di tocco all'angolo in alto a sinistra dell'elemento originale
					initialGhostOffsetX = touch.clientX - rect.left;
					initialGhostOffsetY = touch.clientY - rect.top;

					// Imposta la posizione iniziale del fantasma
					dragGhost.style.left = `${touch.clientX - initialGhostOffsetX}px`;
					dragGhost.style.top = `${touch.clientY - initialGhostOffsetY}px`;
					dragGhost.style.width = `${rect.width}px`;

				} else if (event.dataTransfer) { // Evento drag del mouse (il browser gestisce l'immagine di trascinamento)
					// Nessun dragGhost personalizzato creato qui, il browser lo gestisce.
					// handleDragStart si occupa già dell'immagine di trascinamento del browser.
				}
			};

			const handleDragStart = (event, index) => { // Questa è per il drag-and-drop nativo del desktop (mouse)
				event.dataTransfer.effectAllowed = 'move';

				const originalElement = event.currentTarget.closest('.qrcdr-sortable-item');
				const rect = originalElement.getBoundingClientRect();

				// Crea un clone temporaneo per l'immagine di trascinamento del browser (questo è separato dal nostro 'dragGhost')
				const tempClone = originalElement.cloneNode(true);
				tempClone.classList.add('qrcdr-drag-ghost'); // Applica stili rilevanti all'immagine di trascinamento del browser
				tempClone.style.width = `${rect.width}px`;
				// tempClone.style.boxSizing = 'border-box';

				document.body.appendChild(tempClone); // Appende temporaneamente per setDragImage

				const offsetX = event.clientX - rect.left;
				const offsetY = event.clientY - rect.top;
				event.dataTransfer.setDragImage(tempClone, offsetX, offsetY);

				setTimeout(() => {
					document.body.removeChild(tempClone); // Rimuovi l'elemento temporaneo dopo che il browser ha acquisito l'immagine
				}, 0);

				// Chiama la funzione unificata startDrag per inizializzare lo stato interno, ma non creerà un `dragGhost` per il desktop.
				startDrag(event, index, originalElement);
			};

			const onDropZoneDragEnter = (event) => { event.currentTarget.classList.add('is-active'); };
			const onDropZoneDragLeave = (event) => { event.currentTarget.classList.remove('is-active'); };
			const onDropZoneDragOver = (event) => { event.preventDefault(); };
			const onDropZoneDrop = (event, dropIndex, listName) => {
				event.preventDefault();
				if (draggedItemIndex === null) return;

				const currentList = attributes[listName];
				const reorderedList = reorderArray(currentList, draggedItemIndex, dropIndex);

				const update = {};
				update[listName] = reorderedList;
				setAttributes(update);

				// Resetta lo stato dopo il drop effettivo
				endDrag();
			};

			const endDrag = () => {
				if (dragContainer) {
					dragContainer.classList.remove('is-dragging-active');
				}
				// Rimuovi dragGhost solo se è stato creato (cioè per eventi touch) E se è ancora nel DOM
				if (dragGhost && document.body.contains(dragGhost)) {
					document.body.removeChild(dragGhost);
				}
				dragGhost = null; // Resetta sempre il riferimento a dragGhost
				draggedItemIndex = null;
				dragContainer = null;
				currentTouchElement = null;
				document.querySelectorAll('.is-dragging').forEach(el => el.classList.remove('is-dragging'));
				document.querySelectorAll('.qrcdr-drop-zone.is-active').forEach(el => el.classList.remove('is-active'));
			};

			const onDragEnd = () => {
				endDrag();
			};

			// Touch Event Handlers
			const handleTouchStart = (event, index) => {
				if (event.touches.length !== 1) return; // Solo un touch alla volta
				event.preventDefault(); // Impedisce il default per iniziare il drag

				initialTouchY = event.touches[0].clientY; // Non usata direttamente, ma utile per contesto
				startDrag(event, index, event.currentTarget.closest('.qrcdr-sortable-item')); // Chiama la nuova startDrag
			};

			const handleTouchMove = (event) => {
				if (draggedItemIndex === null || !dragGhost) return;
				event.preventDefault(); // Impedisce lo scrolling mentre si trascina

				const touch = event.touches[0];

				// Usa l'offset iniziale memorizzato per un follow coerente
				dragGhost.style.left = `${touch.clientX - initialGhostOffsetX}px`;
				dragGhost.style.top = `${touch.clientY - initialGhostOffsetY}px`;
				// Simula drag over per le drop zone
				const targetElement = document.elementFromPoint(touch.clientX, touch.clientY);

				// RIMUOVI SEMPRE lo stato attivo da tutte le zone prima di aggiungerlo alla nuova
				document.querySelectorAll('.qrcdr-drop-zone').forEach(el => el.classList.remove('is-active'));


				if (targetElement) {
					// Rimuovi 'is-active' da tutte le drop zone
					// document.querySelectorAll('.qrcdr-drop-zone.is-active').forEach(el => el.classList.remove('is-active'));

					// Se il target è una drop zone, aggiungi 'is-active'
					const dropZone = targetElement.closest('.qrcdr-drop-zone');
					if (dropZone) {
						dropZone.classList.add('is-active');
						currentTouchElement = dropZone;
					} else {
						currentTouchElement = null;
					}
				}
			};

			const handleTouchEnd = (event, listName) => {
				if (draggedItemIndex === null) return;
				event.preventDefault(); // Impedisce l'evento click dopo il drag

				let dropIndex = draggedItemIndex; // Se non c'è una dropzone valida, rimane nella posizione originale

				if (currentTouchElement && currentTouchElement.classList.contains('qrcdr-drop-zone')) {
					// Trova l'indice della drop zone
					const dropZones = Array.from(dragContainer.querySelectorAll('.qrcdr-drop-zone'));
					dropIndex = dropZones.indexOf(currentTouchElement);
				}

				// Chiama la logica di drop
				if (dropIndex !== -1) {
					onDropZoneDrop(event, dropIndex, listName);
				} else {
					// Se non c'è una dropZone valida, assicura che il drag termini correttamente
					endDrag();
				}
			};

			const onChange_qrcdr_sidebar = (value) => { setAttributes({qrcdr_sidebar: value}); };
			const onChange_qrcdr_border_radius_value = (value) => { setAttributes({qrcdr_border_radius_value: value}); };
			const onToggleTab = (tabId, isEnabled) => {
				const newTabs = qrcdr_tabs.map(tab => (tab.id === tabId) ? { ...tab, enabled: isEnabled } : tab);
				setAttributes({ qrcdr_tabs: newTabs });
			};
			const onToggleFeature = (featureId, isEnabled) => {
				const newFeatures = qrcdr_features.map(feature => (feature.id === featureId) ? { ...feature, enabled: isEnabled } : feature);
				setAttributes({ qrcdr_features: newFeatures });
			};
			
			const hexToRgb = (hex) => {if (!hex || typeof hex !== 'string') return { r: 0, g: 0, b: 0 };let r = 0, g = 0, b = 0;if (hex.length === 4) {r = parseInt(hex[1] + hex[1], 16);g = parseInt(hex[2] + hex[2], 16);b = parseInt(hex[3] + hex[3], 16);} else if (hex.length === 7) {r = parseInt(hex.substring(1, 3), 16);g = parseInt(hex.substring(3, 5), 16);b = parseInt(hex.substring(5, 7), 16);}return { r, g, b };};
			const getContrastTextColor = (bgColor) => {const { r, g, b } = hexToRgb(bgColor);const brightness = (r * 299 + g * 587 + b * 114) / 1000;return brightness > 128 ? '#1E1E1E' : '#F6F6F6';};
			// const textColor = getContrastTextColor(qrcdr_color);
			// const reactiveStyles = { borderRadius: `${qrcdr_border_radius_value}px` };
			// const buttonStyles = { backgroundColor: qrcdr_color, color: textColor, ...reactiveStyles };


			// 1. Definiamo i valori "attivi" (se l'attributo è undefined, usa il default globale)
			const activeColor = qrcdr_color !== undefined ? qrcdr_color : QRCDRblock.main_color;
			const activeRadius = qrcdr_border_radius_value !== undefined ? qrcdr_border_radius_value : parseInt(QRCDRblock.border_radius, 10);

			// 2. Usiamo activeColor per il calcolo del contrasto e degli stili
			const textColor = getContrastTextColor(activeColor);
			const reactiveStyles = { borderRadius: `${activeRadius}px` };
			const buttonStyles = { backgroundColor: activeColor, color: textColor, ...reactiveStyles };


			const createSortableList = (items, listName) => {
				if (!Array.isArray(items)) {
					return null;
				}
				const elements = items.reduce((acc, item, index) => {
					// Dropzone prima dell'elemento per posizionare l'elemento SOPRA la dropzone
					acc.push(el('div', { key: `dropzone-${item.id}-${index}`, className: 'qrcdr-drop-zone', onDragOver: onDropZoneDragOver, onDragEnter: onDropZoneDragEnter, onDragLeave: onDropZoneDragLeave, onDrop: (e) => onDropZoneDrop(e, index, listName) }));

					acc.push(el('div', {
						key: item.id, // Usare item.id come chiave unica
						className: `qrcdr-sortable-item ${item.className}`,
					},
						el('div', { className: 'qrcdr-sortable-item-content' },
							el(ToggleControl, {
								label: item.label,
								checked: item.enabled,
								onChange: (isEnabled) => listName === 'qrcdr_tabs' ? onToggleTab(item.id, isEnabled) : onToggleFeature(item.id, isEnabled)
							})
						),
						el('div', { // Drag Handle
							className: 'qrcdr-drag-handle',
							draggable: true, // Questo sarà solo per il mouse
							onDragStart: (e) => handleDragStart(e, index),
							onDragEnd: onDragEnd,
							// Touch events per il drag handle
							onTouchStart: (e) => handleTouchStart(e, index),
							onTouchMove: handleTouchMove,
							onTouchEnd: (e) => handleTouchEnd(e, listName),
							onTouchCancel: endDrag,
						}, dragHandleIcon)
					));
					return acc;
				}, []);

				// Dropzone finale alla fine della lista
				elements.push(el('div', { key: `dropzone-end-${items.length}`, className: 'qrcdr-drop-zone', onDragOver: onDropZoneDragOver, onDragEnter: onDropZoneDragEnter, onDragLeave: onDropZoneDragLeave, onDrop: (e) => onDropZoneDrop(e, items.length, listName) }));

				return el('div', { className: 'qrcdr-sortable-container' }, elements);
			};

			// Assicurati che qrcdr_tabs e qrcdr_features siano sempre array prima di passarli a createSortableList
			// Questo previene errori se gli attributi non sono inizializzati correttamente.
			const currentTabs = Array.isArray(qrcdr_tabs) ? qrcdr_tabs : [];
			const currentFeatures = Array.isArray(qrcdr_features) ? qrcdr_features : [];

			const tabsCheckboxes = createSortableList(currentTabs, 'qrcdr_tabs');
			const featuresCheckboxes = createSortableList(currentFeatures, 'qrcdr_features');
			
			return [
				el( InspectorControls, { key: 'inspector' },
					el( PanelBody, {},
						el( SelectControl, { label: QRCDRblock.i18n.sidebar, value: qrcdr_sidebar, options: selectSidebar, onChange: onChange_qrcdr_sidebar } )
					),
					el( PanelBody, { title: 'Services', initialOpen: true },
						el( 'div', { key: 'tabs-group', className: 'qrcdr-form-group' }, tabsCheckboxes )
					),
					el( PanelBody, { title: 'Features', initialOpen: true },
						el( 'div', { key: 'features-group', className: 'qrcdr-form-group' }, featuresCheckboxes ),
						el( 'p', {}, QRCDRblock.i18n.features_accordion ),
						el( ToggleControl, { label: QRCDRblock.i18n.collapse_options, checked: qrcdr_collapse, onChange: (value) => setAttributes({ qrcdr_collapse: value }) } ),
						el( ToggleControl, { label: QRCDRblock.i18n.single_option_open, checked: qrcdr_single, onChange: (value) => setAttributes({ qrcdr_single: value }) } )
					)
				),
				el( 'div', { ...blockProps, key: 'editor' },
					el( Placeholder, { icon: iconEl, label: "QRcdr" },
						el( 'div', { key: 'placeholder-content' },
							el( 'div', { key: 'color-group', className: 'qrcdr-form-group' },
								el( 'div', {}, 
									el( 'p', {}, QRCDRblock.i18n.primary_color ), 
									el( ColorPalette, { 
										value: activeColor, 
										onChange: (value) => setAttributes({qrcdr_color: value}), 
										clearable: true // Permette di resettare al default globale
									} )
								),
								el( 'div', {}, 
									el( 'p', { className: 'components-base-control__label' }, QRCDRblock.i18n.border_radius ), 
									el( 'div', {}, 
										el( RangeControl, { 
											label: QRCDRblock.i18n.value, 
											value: Number( activeRadius ), // Il cast Number() risolve il campo testo vuoto
											onChange: (value) => setAttributes({ qrcdr_border_radius_value: value }), 
											min: 0, 
											max: 30, 
											step: 1 
										} )
									) 
								),
								el( 'div', {}, el( 'div', {}, el( 'div', { className: 'qrcdr-btn-placeholder', style: buttonStyles }, 'Button' ), el('textarea', { className: 'qrcdr-input-placeholder components-text-control__input', style: reactiveStyles, value: qrcdr_text_field, disabled: true, onChange: ( event ) => setAttributes( { qrcdr_text_field: event.target.value } ) }) ) ),
							)
						)
					)
				)
			];
		},

		save: function (props) {
			const { qrcdr_sidebar, qrcdr_color, qrcdr_collapse, qrcdr_single, qrcdr_tabs, qrcdr_features, qrcdr_border_radius_value } = props.attributes;
			
			const qrcdr_tabs_array = qrcdr_tabs.filter(tab => tab.enabled).map(tab => tab.id);
			const qrcdr_features_array = qrcdr_features.filter(feature => feature.enabled).map(feature => feature.id);

			// Costruiamo lo shortcode dinamicamente
			let shortcode = '[qrcdr';
			shortcode += ' sidebar="' + qrcdr_sidebar + '"';
			
			// Aggiungi solo se personalizzati
			if ( qrcdr_color ) {
				shortcode += ' color="' + qrcdr_color + '"';
			}
			if ( qrcdr_border_radius_value !== undefined ) {
				shortcode += ' border_radius="' + qrcdr_border_radius_value + 'px"';
			}

			shortcode += ' tabs="' + qrcdr_tabs_array.join(',') + '"';
			shortcode += ' features="' + qrcdr_features_array.join(',') + '"';
			shortcode += ' collapse="' + qrcdr_collapse + '"';
			shortcode += ' single="' + qrcdr_single + '"';
			shortcode += ']';

			return shortcode;
		},
	});
})(
	window.wp.blocks,
	window.wp.element,
	window.wp.blockEditor,
	window.wp.components
);