/**
 * Design → collection items list (cards, FAQ, tabs, plans, …).
 * Same chrome as SlidesList / CardsList.
 */
import { useState } from '@wordpress/element';
import { Button } from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
import {
	collectionItemNoun,
	collectionItemListLines,
} from '../shared/collectionRepeater';
/**
 * @param {Array} items
 * @param {number} from
 * @param {number} to
 * @return {Array}
 */
export function reorderCollectionArray( items, from, to ) {
	if (
		! Array.isArray( items ) ||
		from === to ||
		from == null ||
		to == null ||
		from < 0 ||
		to < 0 ||
		from >= items.length ||
		to >= items.length
	) {
		return items;
	}
	let next;
	try {
		next = JSON.parse( JSON.stringify( items ) );
	} catch ( e ) {
		next = items.map( ( row ) =>
			row && typeof row === 'object' ? { ...row } : row
		);
	}
	const [ item ] = next.splice( from, 1 );
	next.splice( to, 0, item );
	return next;
}

/**
 * @param {number|null} focusIndex
 * @param {number} from
 * @param {number} to
 * @return {number|null}
 */
export function remapFocusCollectionIndex( focusIndex, from, to ) {
	if ( focusIndex == null || from === to ) {
		return focusIndex;
	}
	if ( focusIndex === from ) {
		return to;
	}
	if ( from < to && focusIndex > from && focusIndex <= to ) {
		return focusIndex - 1;
	}
	if ( from > to && focusIndex >= to && focusIndex < from ) {
		return focusIndex + 1;
	}
	return focusIndex;
}

/** @deprecated Use reorderCollectionArray */
export function reorderCardsArray( cards, from, to ) {
	return reorderCollectionArray( cards, from, to );
}

/** @deprecated Use remapFocusCollectionIndex */
export function remapFocusCardIndex( focusIndex, from, to ) {
	return remapFocusCollectionIndex( focusIndex, from, to );
}

function isInteractiveTarget( target ) {
	if ( ! ( target instanceof Element ) ) {
		return false;
	}
	return Boolean(
		target.closest(
			'button, a, input, select, textarea, [role="button"], .components-button'
		)
	);
}

/**
 * @param {object}   props
 * @param {Array}    [props.items]
 * @param {Array}    [props.cards]  Alias of items (legacy)
 * @param {object}   [props.field]  Collection repeater field (for labels)
 * @param {string}   [props.itemNoun]
 * @param {Function} props.onReorder
 * @param {Function} props.onOpen
 * @param {Function} props.onRemove
 * @param {number}   [props.minItems]
 * @param {number}   [props.minCards]
 */
export default function CardsList( {
	items,
	cards,
	field = {},
	itemNoun: itemNounProp,
	onReorder,
	onOpen,
	onRemove,
	minItems,
	minCards = 1,
} ) {
	const list = Array.isArray( items )
		? items
		: Array.isArray( cards )
			? cards
			: [];
	const [ dragIndex, setDragIndex ] = useState( null );
	const [ overIndex, setOverIndex ] = useState( null );
	const floor = minItems != null ? minItems : minCards;
	const canRemove = list.length > floor;
	const canDrag = list.length > 1;
	const noun = itemNounProp || collectionItemNoun( field );

	const move = ( index, dir ) => {
		const target = index + dir;
		if ( target < 0 || target >= list.length ) {
			return;
		}
		const next = reorderCollectionArray( list, index, target );
		onReorder?.( next, { from: index, to: target } );
	};

	const reorder = ( from, to ) => {
		const next = reorderCollectionArray( list, from, to );
		if ( next === list ) {
			return;
		}
		onReorder?.( next, { from, to } );
	};

	return (
		<div className="bm-slides-list-wrap">
			{ canDrag ? (
				<p className="bm-slides-list__hint">
					{ __(
						'Drag an item to reorder, or use the arrows.',
						'joc-blockora-morph'
					) }
				</p>
			) : null }
			<ul className="bm-slides-list" role="list">
				{ list.map( ( item, index ) => {
					const isDragging = dragIndex === index;
					const isOver = overIndex === index && dragIndex !== index;
					const title = sprintf(
						/* translators: 1: item noun, 2: number */
						__( '%1$s %2$d', 'joc-blockora-morph' ),
						noun,
						index + 1
					);
					const lines = collectionItemListLines( item );
					const previewTitle = lines.title
						? lines.title.slice( 0, 48 )
						: '';
					const previewDesc = lines.description
						? lines.description.slice( 0, 72 )
						: lines.fallback
							? lines.fallback.slice( 0, 72 )
							: '';

					return (
						<li
							key={ `collection-row-${ index }` }
							className={ [
								'bm-slides-list__item',
								canDrag ? 'is-draggable' : '',
								isDragging ? 'is-dragging' : '',
								isOver ? 'is-drop-target' : '',
							]
								.filter( Boolean )
								.join( ' ' ) }
							draggable={ canDrag }
							onMouseDown={ ( e ) => {
								if ( ! isInteractiveTarget( e.target ) ) {
									e.stopPropagation();
								}
							} }
							onDragStart={ ( e ) => {
								if (
									! canDrag ||
									isInteractiveTarget( e.target )
								) {
									e.preventDefault();
									return;
								}
								e.stopPropagation();
								setDragIndex( index );
								e.dataTransfer.effectAllowed = 'move';
								e.dataTransfer.setData(
									'text/plain',
									String( index )
								);
								if ( e.currentTarget instanceof HTMLElement ) {
									e.dataTransfer.setDragImage(
										e.currentTarget,
										24,
										24
									);
								}
							} }
							onDragEnd={ () => {
								setDragIndex( null );
								setOverIndex( null );
							} }
							onDragOver={ ( e ) => {
								if ( ! canDrag ) {
									return;
								}
								e.preventDefault();
								e.stopPropagation();
								e.dataTransfer.dropEffect = 'move';
								if ( overIndex !== index ) {
									setOverIndex( index );
								}
							} }
							onDragLeave={ () => {
								if ( overIndex === index ) {
									setOverIndex( null );
								}
							} }
							onDrop={ ( e ) => {
								if ( ! canDrag ) {
									return;
								}
								e.preventDefault();
								e.stopPropagation();
								const fromRaw =
									e.dataTransfer.getData( 'text/plain' );
								const from =
									fromRaw !== ''
										? parseInt( fromRaw, 10 )
										: dragIndex;
								reorder( from, index );
								setDragIndex( null );
								setOverIndex( null );
							} }
						>
							<span
								className="bm-slides-list__handle"
								title={ __(
									'Drag to reorder',
									'joc-blockora-morph'
								) }
								aria-hidden="true"
							>
								<span className="dashicons dashicons-menu" />
							</span>

							<span
								className="bm-slides-list__index"
								aria-hidden="true"
							>
								{ index + 1 }
							</span>

							{ canRemove ? (
								<Button
									size="small"
									variant="tertiary"
									isDestructive
									className="bm-slides-list__delete"
									icon="trash"
									draggable={ false }
									onClick={ ( e ) => {
										e.preventDefault();
										e.stopPropagation();
										onRemove?.( index );
									} }
									aria-label={ sprintf(
										/* translators: 1: item noun, 2: number */
										__(
											'Delete %1$s %2$d',
											'joc-blockora-morph'
										),
										noun,
										index + 1
									) }
								/>
							) : (
								<span
									className="bm-slides-list__delete-spacer"
									aria-hidden="true"
								/>
							) }

							<button
								type="button"
								className="bm-slides-list__main"
								draggable={ false }
								onClick={ () => onOpen?.( index ) }
							>
								<span className="bm-slides-list__title-block">
									<span className="bm-slides-list__title">
										{ title }
									</span>
									{ previewTitle ? (
										<span className="bm-slides-list__preview">
											{ previewTitle }
										</span>
									) : null }
									{ previewDesc ? (
										<span className="bm-slides-list__preview bm-slides-list__preview--desc">
											{ previewDesc }
										</span>
									) : null }
								</span>
								<span
									className="dashicons dashicons-arrow-right-alt2 bm-slides-list__chevron"
									aria-hidden="true"
								/>
							</button>

							<div className="bm-slides-list__move">
								<Button
									size="small"
									variant="tertiary"
									className="bm-slides-list__icon-btn"
									disabled={ index === 0 }
									draggable={ false }
									onClick={ ( e ) => {
										e.stopPropagation();
										move( index, -1 );
									} }
									aria-label={ __(
										'Move up',
										'joc-blockora-morph'
									) }
									icon="arrow-up-alt2"
								/>
								<Button
									size="small"
									variant="tertiary"
									className="bm-slides-list__icon-btn"
									disabled={ index === list.length - 1 }
									draggable={ false }
									onClick={ ( e ) => {
										e.stopPropagation();
										move( index, 1 );
									} }
									aria-label={ __(
										'Move down',
										'joc-blockora-morph'
									) }
									icon="arrow-down-alt2"
								/>
							</div>
						</li>
					);
				} ) }
			</ul>
		</div>
	);
}
