import React, { useEffect, useId, useMemo, useRef, useState } from 'react';
import { __, sprintf } from '@wordpress/i18n';
import { Alert, Button, Icon, IconButton, Portal, Skeleton, SkeletonGroup, useEscape, useFocusTrap, useScrollLock } from '../../shared/ui';
import useBookingFlow from './useBookingFlow';
import { AgentStep, CategoryStep, ExtrasStep, LocationStep, ServiceStep } from './components/ChoiceSteps';
import DateTimeStep from './components/DateTimeStep';
import DetailsStep from './components/DetailsStep';
import PaymentStep from './components/PaymentStep';
import ReviewStep from './components/ReviewStep';
import ConfirmationStep from './components/ConfirmationStep';
import { SummaryBar, SummaryPanel } from './components/Summary';
import { formatMoney } from './format';
import { paymentMeta } from './payments';

function Progress({ flow }) {
	const { visibleSteps, stepKey, history, stepCfg } = flow;
	const idx = Math.max(0, visibleSteps.indexOf(stepKey));
	const total = visibleSteps.length;
	if (stepKey === 'confirmation' || total < 2) return null;
	return (
		<nav className="bp-bw-progress" aria-label={__('Booking progress', 'pointly-booking')}>
			<p className="bp-bw-progress__count">
				{
					/* translators: 1: current step number, 2: total number of steps. */
					sprintf(__('Step %1$d of %2$d', 'pointly-booking'), idx + 1, total)
				}
			</p>
			<ol className="bp-bw-steps">
				{visibleSteps.map((k, i) => {
					const done = history.includes(k);
					const current = k === stepKey;
					const cls = ['bp-bw-steps__item', done ? 'is-done' : '', current ? 'is-current' : ''].filter(Boolean).join(' ');
					const inner = (
						<>
							<span className="bp-bw-steps__marker" aria-hidden="true">
								{done ? <Icon name="check" /> : i + 1}
							</span>
							<span className="bp-bw-steps__label">{stepCfg[k].short}</span>
						</>
					);
					return (
						<li key={k} className={cls}>
							{done ? (
								<button type="button" className="bp-bw-steps__btn" onClick={() => flow.actions.goTo(k)}>
									{inner}
									<span className="bp-visually-hidden">{__('(completed, edit)', 'pointly-booking')}</span>
								</button>
							) : (
								<span className="bp-bw-steps__btn" aria-current={current ? 'step' : undefined}>
									{inner}
								</span>
							)}
						</li>
					);
				})}
			</ol>
			<div className="bp-bw-progress__bar" aria-hidden="true">
				<span style={{ '--_value': `${((idx + 1) / total) * 100}%` }} />
			</div>
		</nav>
	);
}

function StepBody({ flow, headingId }) {
	switch (flow.stepKey) {
		case 'location':
			return <LocationStep flow={flow} labelledBy={headingId} />;
		case 'category':
			return <CategoryStep flow={flow} labelledBy={headingId} />;
		case 'service':
			return <ServiceStep flow={flow} labelledBy={headingId} />;
		case 'extras':
			return <ExtrasStep flow={flow} labelledBy={headingId} />;
		case 'agent':
			return <AgentStep flow={flow} labelledBy={headingId} />;
		case 'datetime':
			return <DateTimeStep flow={flow} headingId={headingId} />;
		case 'customer':
			return <DetailsStep flow={flow} />;
		case 'payment':
			return <PaymentStep flow={flow} labelledBy={headingId} />;
		case 'review':
			return <ReviewStep flow={flow} />;
		default:
			return null;
	}
}

function continueLabel(flow) {
	const cfg = flow.stepCfg[flow.stepKey];
	if (cfg && cfg.nextLabel) return { label: cfg.nextLabel, icon: undefined };
	if (flow.stepKey !== 'review') return { label: __('Continue', 'pointly-booking'), icon: undefined };
	const total = flow.pricing ? flow.pricing.total : 0;
	if (total <= 0 || !paymentMeta(flow.paymentMethod).online) return { label: __('Confirm booking', 'pointly-booking'), icon: 'check' };
	if (flow.paymentMethod === 'stripe' && window.pointlybooking_FRONT?.stripe_pk) return { label: __('Continue to payment', 'pointly-booking'), icon: 'lock' };
	return { label: sprintf(/* translators: %s: amount, e.g. "$30". */ __('Pay %s', 'pointly-booking'), formatMoney(total, flow.pricing.currency)), icon: 'lock' };
}

/**
 * The booking wizard UI. `onClose` is only given in modal mode.
 */
export default function BookingApp({ presets, onClose, headingId: headingIdProp, autoStart = true, className = '' }) {
	const flow = useBookingFlow(presets);
	const autoId = useId().replace(/:/g, '');
	const headingId = headingIdProp || `bp-bw-h-${autoId}`;
	const headingRef = useRef(null);
	const contentRef = useRef(null);
	const interacted = useRef(false);
	const { stepKey, stepCfg, resolving } = flow;

	useEffect(() => {
		if (autoStart) flow.actions.start();
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [autoStart]);

	// Keep the customer oriented: new step → title focused (screen readers) and
	// scrolled into view. Not on the very first render of an inline widget.
	useEffect(() => {
		if (!stepKey) return;
		if (!interacted.current) {
			interacted.current = true;
			if (!onClose) return;
		}
		if (headingRef.current) {
			headingRef.current.focus({ preventScroll: true });
			if (!onClose && headingRef.current.getBoundingClientRect().top < 0) {
				headingRef.current.scrollIntoView({ block: 'start', behavior: 'auto' });
			}
		}
		if (contentRef.current) contentRef.current.scrollTop = 0;
	}, [stepKey, onClose]);

	const cfg = stepCfg[stepKey] || null;
	const isConfirmation = stepKey === 'confirmation';
	const isReview = stepKey === 'review';
	const paying = isReview && !!flow.pay;
	const canBack = flow.history.length > 0 && !isConfirmation;
	const showFooter = stepKey && stepKey !== 'error' && !isConfirmation && !paying;
	const showSummary = stepKey && stepKey !== 'error' && !isConfirmation;
	const cont = useMemo(() => continueLabel(flow), [flow.stepKey, flow.pricing, flow.paymentMethod, stepCfg]); // eslint-disable-line react-hooks/exhaustive-deps

	const primary = () => (isReview ? flow.actions.submit() : flow.actions.next());
	const onKeyDown = (e) => {
		if (e.key !== 'Enter' || stepKey !== 'customer' || e.defaultPrevented) return;
		const t = e.target;
		if (t && t.tagName === 'INPUT' && t.type !== 'checkbox') {
			e.preventDefault();
			flow.actions.next();
		}
	};

	let body;
	if (!stepKey || (resolving && !stepKey)) {
		body = (
			<SkeletonGroup label={__('Loading the booking form…', 'pointly-booking')} className="bp-bw-skel">
				<Skeleton height={72} />
				<Skeleton height={72} />
				<Skeleton height={72} />
			</SkeletonGroup>
		);
	} else if (stepKey === 'error') {
		body = (
			<Alert tone="danger" live title={__('The booking form could not be loaded', 'pointly-booking')}>
				{flow.loadError}{' '}
				<Button
					variant="link"
					onClick={() => {
						flow.actions.reset();
					}}
				>
					{__('Try again', 'pointly-booking')}
				</Button>
			</Alert>
		);
	} else if (isConfirmation) {
		body = (
			<ConfirmationStep
				id={flow.result.id}
				method={flow.result.method}
				bookingKey={flow.result.key}
				onAnother={flow.actions.reset}
				onClose={onClose || flow.actions.reset}
				onRetryPayment={flow.actions.reset}
			/>
		);
	} else {
		body = <StepBody flow={flow} headingId={headingId} />;
	}

	const heading = stepKey === 'error' ? __('Book an appointment', 'pointly-booking') : cfg ? cfg.title : __('Book an appointment', 'pointly-booking');
	const sub = cfg && !isConfirmation ? cfg.subtitle : '';
	const accent = cfg && cfg.accent && /^#[0-9a-f]{3,8}$/i.test(cfg.accent) ? { '--bp-c-primary': cfg.accent } : undefined;

	return (
		<div className={['bp-bw', onClose ? 'bp-bw--modal' : 'bp-bw--inline', className].filter(Boolean).join(' ')} style={accent} data-step={stepKey || 'loading'}>
			<header className="bp-bw__header">
				<div className="bp-bw__titles">
					<h2 className={['bp-bw__title', isConfirmation ? 'bp-visually-hidden' : ''].filter(Boolean).join(' ')} id={headingId} ref={headingRef} tabIndex={-1}>
						{heading}
					</h2>
					{sub ? <p className="bp-bw__subtitle">{sub}</p> : null}
				</div>
				{onClose ? <IconButton icon="x" label={__('Close', 'pointly-booking')} variant="ghost" onClick={onClose} /> : null}
			</header>

			<Progress flow={flow} />

			<div className="bp-bw__content" ref={contentRef}>
				<div className="bp-bw__main" onKeyDown={onKeyDown} aria-busy={resolving ? 'true' : undefined}>
					{body}
				</div>
				{showSummary ? <SummaryPanel flow={flow} /> : null}
			</div>

			{showSummary ? <SummaryBar flow={flow} /> : null}

			{showFooter ? (
				<footer className="bp-bw__footer">
					{canBack ? (
						<Button variant="ghost" icon="arrow-left" className="bp-bw__back" onClick={flow.actions.back} disabled={flow.submitting}>
							{cfg && cfg.backLabel ? cfg.backLabel : __('Back', 'pointly-booking')}
						</Button>
					) : (
						<span />
					)}
					<Button
						variant="primary"
						size="lg"
						className="bp-bw__continue"
						iconEnd={cont.icon ? undefined : 'arrow-right'}
						icon={cont.icon}
						loading={resolving || flow.submitting}
						disabled={!flow.canContinue && !isReview}
						onClick={primary}
					>
						{cont.label}
					</Button>
				</footer>
			) : null}
		</div>
	);
}

/**
 * Full-screen (mobile) / centred (desktop) dialog around the wizard.
 */
export function BookingDialog({ open, onClose, labelledBy, children }) {
	const [node, setNode] = useState(null);
	useFocusTrap(node, open && !!node);
	useScrollLock(open);
	useEscape(() => onClose && onClose(), open);
	if (!open) return null;
	return (
		<Portal>
			<div className="bp-overlay bp-bw-overlay">
				<div ref={setNode} role="dialog" aria-modal="true" aria-labelledby={labelledBy} tabIndex={-1} className="bp-modal bp-modal--xl bp-bw-dialog">
					{children}
				</div>
			</div>
		</Portal>
	);
}
