import React, { createContext, useCallback, useContext, useId, useRef, useState } from 'react';
import { __ } from '@wordpress/i18n';
import { Portal } from './core';
import Button, { IconButton } from './Button';
import { useEscape, useFocusTrap, useScrollLock } from './hooks';

function useDialog({ open, onClose, initialFocusRef, closeOnEsc = true }) {
	// Callback ref kept in state: the dialog only exists once its portal has
	// mounted, and the focus trap must run at that moment.
	const [node, setNode] = useState(null);
	useFocusTrap(node, open && !!node, { initialFocusRef });
	useScrollLock(open);
	useEscape(() => closeOnEsc && onClose && onClose(), open);
	return setNode;
}

/**
 * Modal dialog. Full-screen below 640px (or a bottom sheet with `sheet`).
 *
 * @param {'sm'|'md'|'lg'|'xl'} [size='md']
 */
export function Modal({
	open,
	onClose,
	title,
	description,
	children,
	footer,
	size = 'md',
	sheet = false,
	initialFocusRef,
	closeOnOverlay = true,
	hideClose = false,
	className = '',
	labelledBy,
}) {
	const autoId = useId().replace(/:/g, '');
	const titleId = labelledBy || `bp-modal-t-${autoId}`;
	const descId = description ? `bp-modal-d-${autoId}` : undefined;
	const ref = useDialog({ open, onClose, initialFocusRef });
	if (!open) return null;

	return (
		<Portal>
			<div
				className="bp-overlay"
				onMouseDown={(e) => {
					if (closeOnOverlay && e.target === e.currentTarget && onClose) onClose();
				}}
			>
				<div
					ref={ref}
					role="dialog"
					aria-modal="true"
					aria-labelledby={title || labelledBy ? titleId : undefined}
					aria-describedby={descId}
					tabIndex={-1}
					className={['bp-modal', size !== 'md' ? `bp-modal--${size}` : '', sheet ? 'bp-modal--sheet' : '', className].filter(Boolean).join(' ')}
				>
					{title || !hideClose ? (
						<div className="bp-modal__header">
							<div style={{ minWidth: 0 }}>
								{title ? (
									<h2 className="bp-modal__title" id={titleId}>
										{title}
									</h2>
								) : null}
								{description ? (
									<p className="bp-modal__desc" id={descId}>
										{description}
									</p>
								) : null}
							</div>
							{!hideClose ? <IconButton icon="x" label={__('Close', 'pointly-booking')} className="bp-modal__close" onClick={onClose} /> : null}
						</div>
					) : null}
					<div className="bp-modal__body">{children}</div>
					{footer ? <div className="bp-modal__footer">{footer}</div> : null}
				</div>
			</div>
		</Portal>
	);
}

/**
 * Slide-in side panel (from the inline end: right in LTR, left in RTL).
 */
export function Drawer({ open, onClose, title, subtitle, headerExtra, children, footer, size = 'md', initialFocusRef, className = '' }) {
	const autoId = useId().replace(/:/g, '');
	const titleId = `bp-drawer-t-${autoId}`;
	const ref = useDialog({ open, onClose, initialFocusRef });
	if (!open) return null;

	return (
		<Portal>
			<div
				className="bp-overlay bp-overlay--drawer"
				onMouseDown={(e) => {
					if (e.target === e.currentTarget && onClose) onClose();
				}}
			>
				<aside
					ref={ref}
					role="dialog"
					aria-modal="true"
					aria-labelledby={titleId}
					tabIndex={-1}
					className={['bp-drawer', size !== 'md' ? `bp-drawer--${size}` : '', className].filter(Boolean).join(' ')}
				>
					<div className="bp-drawer__header">
						<div style={{ minWidth: 0 }}>
							<h2 className="bp-drawer__title" id={titleId}>
								{title}
							</h2>
							{subtitle ? <p className="bp-drawer__subtitle">{subtitle}</p> : null}
						</div>
						<div className="bp-cluster" style={{ flexWrap: 'nowrap' }}>
							{headerExtra}
							<IconButton icon="x" label={__('Close', 'pointly-booking')} onClick={onClose} />
						</div>
					</div>
					<div className="bp-drawer__body">{children}</div>
					{footer ? <div className="bp-drawer__footer">{footer}</div> : null}
				</aside>
			</div>
		</Portal>
	);
}

/* ---- Confirm dialog (promise based) ---- */
const ConfirmContext = createContext(null);

/**
 * Provides `useConfirm()`:
 *   const confirm = useConfirm();
 *   if (await confirm({ title, message, confirmLabel, danger: true })) { … }
 */
export function ConfirmProvider({ children }) {
	const [state, setState] = useState(null);
	const cancelRef = useRef(null);

	const confirm = useCallback(
		(opts = {}) =>
			new Promise((resolve) => {
				setState({ ...opts, resolve });
			}),
		[]
	);

	const finish = (result) => {
		if (state && state.resolve) state.resolve(result);
		setState(null);
	};

	return (
		<ConfirmContext.Provider value={confirm}>
			{children}
			<Modal
				open={!!state}
				onClose={() => finish(false)}
				title={state?.title || __('Are you sure?', 'pointly-booking')}
				size="sm"
				initialFocusRef={cancelRef}
				footer={
					<>
						<Button ref={cancelRef} variant="secondary" onClick={() => finish(false)}>
							{state?.cancelLabel || __('Cancel', 'pointly-booking')}
						</Button>
						<Button variant={state?.danger ? 'danger' : 'primary'} onClick={() => finish(true)}>
							{state?.confirmLabel || __('Confirm', 'pointly-booking')}
						</Button>
					</>
				}
			>
				{state?.message ? <p className="bp-text-muted">{state.message}</p> : null}
			</Modal>
		</ConfirmContext.Provider>
	);
}

export function useConfirm() {
	const ctx = useContext(ConfirmContext);
	return (
		ctx ||
		((opts = {}) =>
			// eslint-disable-next-line no-alert
			Promise.resolve(window.confirm(opts.message || opts.title || __('Are you sure?', 'pointly-booking'))))
	);
}
