/**
 * WordPress dependencies
 */
import { Button, ColorIndicator, Icon } from '@safe-wordpress/components';
import { useDispatch } from '@safe-wordpress/data';
import { useRef } from '@safe-wordpress/element';
import * as Icons from '@safe-wordpress/icons';
import { _x } from '@safe-wordpress/i18n';
type IconKey = keyof typeof Icons;

/**
 * External dependencies
 */
import { clsx } from 'clsx';
import { useDrag, useDrop, type XYCoord } from 'react-dnd';
import { DeleteButton } from '@nelio-content/components';
import type { PostStatusSlug } from '@nelio-content/types';

/**
 * Internal dependencies
 */
import './style.scss';

import { store as NC_CUSTOM_STATUSES } from '~/nelio-content-pages/settings/custom-statuses/store';
import {
	useStatus,
	useIsSaving,
} from '~/nelio-content-pages/settings/custom-statuses/hooks';

type DragItem = {
	index: number;
	id: PostStatusSlug;
	type: string;
};

export type StatusProps = {
	readonly index: number;
	readonly slug: PostStatusSlug;
	readonly onMove: ( dragIndex: number, hoverIndex: number ) => void;
	readonly onDragStart: () => void;
	readonly onDragEnd: () => void;
};

export const Status = ( {
	index,
	slug,
	onMove,
	onDragStart,
	onDragEnd,
}: StatusProps ): JSX.Element | null => {
	const status = useStatus( slug );
	const isSaving = useIsSaving();
	const { openStatusEditor, removeStatus } =
		useDispatch( NC_CUSTOM_STATUSES );

	const ref = useRef< HTMLDivElement >( null );

	const [ _, dropReference ] = useDrop< DragItem >( {
		accept: 'status',
		hover: ( dragItem, monitor ) => {
			if ( ! ref.current ) {
				return;
			}
			const dragIndex = dragItem.index;
			const hoverIndex = index;

			// Don't replace items with themselves
			if ( dragIndex === hoverIndex ) {
				return;
			}

			// Determine rectangle on screen
			const hoverBoundingRect = ref.current?.getBoundingClientRect();

			// Get vertical middle
			const hoverMiddleY =
				( hoverBoundingRect.bottom - hoverBoundingRect.top ) / 2;

			// Determine mouse position
			const clientOffset = monitor.getClientOffset();

			// Get pixels to the top
			const hoverClientY =
				( clientOffset as XYCoord ).y - hoverBoundingRect.top;

			// Only perform the move when the mouse has crossed half of the items height
			// When dragging downwards, only move when the cursor is below 50%
			// When dragging upwards, only move when the cursor is above 50%

			// Dragging downwards
			if ( dragIndex < hoverIndex && hoverClientY < hoverMiddleY ) {
				return;
			}

			// Dragging upwards
			if ( dragIndex > hoverIndex && hoverClientY > hoverMiddleY ) {
				return;
			}

			// Time to actually perform the action
			onMove( dragIndex, hoverIndex );

			// Note: we're mutating the monitor item here!
			// Generally it's better to avoid mutations,
			// but it's good here for the sake of performance
			// to avoid expensive index searches.
			dragItem.index = hoverIndex;
		},
	} );

	const [ { isDragging }, dragReference ] = useDrag( {
		type: 'status',
		item: () => {
			onDragStart();
			return { id: status?.slug, index };
		},
		end: onDragEnd,
		collect: ( monitor ) => ( {
			isDragging: monitor.isDragging(),
		} ),
	} );

	dropReference( dragReference( ref ) );

	if ( ! status ) {
		return null;
	}

	return (
		<div
			className={ clsx( 'nelio-content-status', {
				'nelio-content-status--is-dragging': isDragging,
			} ) }
			ref={ ref }
		>
			<div className="nelio-content-status__handler">
				<Icon
					icon={
						( Icons as unknown as Record< IconKey, JSX.Element > )[
							'dragHandle' as IconKey
						] ?? Icons.swatch
					}
				/>
			</div>
			<div className="nelio-content-status__content">
				<div className="nelio-content-status__header">
					<div className="nelio-content-status__icon">
						<Icon
							icon={
								(
									Icons as unknown as Record<
										IconKey,
										JSX.Element
									>
								 )[ status.icon as IconKey ] ?? Icons.swatch
							}
						/>
					</div>
					<div className="nelio-content-status__name">
						<Button
							className="nelio-content-status__name--link"
							variant="link"
							disabled={ isSaving }
							onClick={ () => void openStatusEditor( status ) }
						>
							{ status.name }
						</Button>
						<span className="nelio-content-status__name--core">
							{ status.core ? ' — Core' : '' }
						</span>
					</div>
					<div className="nelio-content-status__colors">
						<ColorIndicator
							className="nelio-content-status__main-color"
							colorValue={ status.colors?.main }
						/>
						<ColorIndicator
							className="nelio-content-status__background-color"
							colorValue={ status.colors?.background }
						/>
					</div>
				</div>
				<div className="nelio-content-status__details">
					{ status.description }
				</div>
				<div className="nelio-content-status__actions">
					<Button
						variant="link"
						disabled={ isSaving }
						onClick={ () => void openStatusEditor( status ) }
					>
						{ _x( 'Edit', 'command', 'nelio-content' ) }
					</Button>
					{ ! status.isCustomizationLimited && (
						<>
							{ ' | ' }
							<DeleteButton
								disabled={ isSaving }
								onClick={ () => removeStatus( slug ) }
							/>
						</>
					) }
				</div>
			</div>
		</div>
	);
};
