/**
 * WordPress dependencies
 */
import domReady from '@safe-wordpress/dom-ready';
import { useRef, useState } from '@safe-wordpress/element';
import { _x } from '@safe-wordpress/i18n';

/**
 * External dependencies
 */
import clsx from 'clsx';
import { usePageAttribute } from '@nab/data';
import { setValue, getValue, clearValue } from '@nab/utils';
import type { AlternativeId } from '@nab/types';

/**
 * Internal dependencies
 */
import './style.scss';
import { Sidebar } from '../sidebar';
import { PhpPreview } from '../preview';

export type LayoutProps = {
	readonly alternativeId: AlternativeId;
};

const MIN_SIDEBAR_WIDTH = 320;
const SETTING_NAME = 'php-editor-sidebar-width';

const STYLE = document.createElement( 'style' );
function setWidth( width: number ) {
	width = ! isNaN( width ) ? width : MIN_SIDEBAR_WIDTH;
	width = Math.min( width, window.innerWidth - MIN_SIDEBAR_WIDTH );
	width = Math.max( width, MIN_SIDEBAR_WIDTH );
	STYLE.textContent = `:root{--nab-php-editor-sidebar-width: ${ width }px;}`;
	setValue( SETTING_NAME, width );
}

domReady( () => {
	document.head.appendChild( STYLE );
	setWidth( Number.parseInt( getValue( SETTING_NAME, '' ) ) );
} );

export const Layout = ( { alternativeId }: LayoutProps ): JSX.Element => {
	const [ areControlsVisible ] = usePageAttribute(
		'php-preview/areControlsVisible',
		true
	);

	const dividerRef = useRef( null );
	const [ isDragging, setIsDragging ] = useState( false );

	return (
		<div
			className={ clsx( {
				'nab-php-editor': true,
				'nab-php-editor--is-dragging': isDragging,
			} ) }
		>
			<Sidebar
				className={ clsx( {
					'nab-php-editor__sidebar': true,
					'nab-php-editor__sidebar--is-collapsed':
						! areControlsVisible,
				} ) }
				alternativeId={ alternativeId }
			/>

			<Divider
				dividerRef={ dividerRef }
				onDragStart={ () => setIsDragging( true ) }
				onDrag={ setWidth }
				onDragEnd={ () => setIsDragging( false ) }
				onDoubleClick={ () => {
					setIsDragging( true );
					setTimeout( () => {
						STYLE.textContent = '';
						setTimeout( () => setIsDragging( false ), 200 );
						clearValue( SETTING_NAME );
					}, 0 );
				} }
			/>

			<PhpPreview
				key="nab-php-editor__preview"
				className={ clsx( {
					'nab-php-editor__preview': true,
					'nab-php-editor__preview--is-fullscreen':
						! areControlsVisible,
				} ) }
				alternativeId={ alternativeId }
			/>
		</div>
	);
};

type DividerProps = {
	readonly dividerRef: React.MutableRefObject< null >;
	readonly onDragStart?: () => void;
	readonly onDrag?: ( x: number ) => void;
	readonly onDragEnd?: () => void;
	readonly onDoubleClick?: () => void;
};
const Divider = ( {
	dividerRef,
	onDragStart,
	onDrag,
	onDragEnd,
	onDoubleClick,
}: DividerProps ) => {
	const onPointerDown: React.PointerEventHandler< HTMLDivElement > = (
		e
	) => {
		e.currentTarget.setPointerCapture( e.pointerId );
		onDragStart?.();
	};

	const onPointerMove: React.PointerEventHandler< HTMLDivElement > = (
		e
	) => {
		if ( e.currentTarget.hasPointerCapture( e.pointerId ) ) {
			onDrag?.( e.clientX );
		}
	};

	const onPointerUp: React.PointerEventHandler< HTMLDivElement > = ( e ) => {
		if ( e.currentTarget.hasPointerCapture( e.pointerId ) ) {
			e.currentTarget.releasePointerCapture( e.pointerId );
		}
		onDragEnd?.();
	};

	return (
		<div
			ref={ dividerRef }
			className="nab-php-editor__resizer"
			role="separator"
			aria-orientation="vertical"
			aria-label={ _x( 'Resize Editor', 'command', 'nelio-ab-testing' ) }
			tabIndex={ 0 }
			onPointerDown={ onPointerDown }
			onPointerMove={ onPointerMove }
			onPointerUp={ onPointerUp }
			onDoubleClick={ onDoubleClick }
		/>
	);
};
