import React, { useEffect, useId, useMemo, useRef, useState } from 'react';
import { __, sprintf } from '@wordpress/i18n';
import { Icon, Spinner, useDebouncedValue, useEscape, useOnClickOutside } from '../../shared/ui';
import api from '../core/api';
import { adminUrl, formatWhen } from '../core/format';
import { useAdmin } from '../core/AdminContext';

/**
 * Top-bar search across bookings, customers and services (GET /admin/search).
 * Combobox pattern: the input keeps focus, arrows move the highlighted result.
 */
export default function GlobalSearch() {
	const { openBooking } = useAdmin();
	const [q, setQ] = useState('');
	const [open, setOpen] = useState(false);
	const [loading, setLoading] = useState(false);
	const [results, setResults] = useState(null);
	const [error, setError] = useState('');
	const [active, setActive] = useState(0);
	const rootRef = useRef(null);
	const inputRef = useRef(null);
	const listId = `bp-gs-${useId().replace(/:/g, '')}`;
	const debounced = useDebouncedValue(q.trim(), 250);

	useEscape(() => setOpen(false), open);
	useOnClickOutside(rootRef, () => setOpen(false), open);

	// Press "/" anywhere (outside inputs) to jump to the search.
	useEffect(() => {
		const onKey = (e) => {
			if (e.key !== '/' || e.metaKey || e.ctrlKey || e.altKey) return;
			const t = e.target;
			if (t && (t.tagName === 'INPUT' || t.tagName === 'TEXTAREA' || t.tagName === 'SELECT' || t.isContentEditable)) return;
			e.preventDefault();
			if (inputRef.current) inputRef.current.focus();
		};
		document.addEventListener('keydown', onKey);
		return () => document.removeEventListener('keydown', onKey);
	}, []);

	useEffect(() => {
		if (debounced.length < 2) {
			setResults(null);
			setLoading(false);
			return undefined;
		}
		let alive = true;
		setLoading(true);
		setError('');
		api.get('/admin/search', { q: debounced })
			.then((d) => alive && (setResults(d), setActive(0)))
			.catch((e) => alive && setError(e.message))
			.finally(() => alive && setLoading(false));
		return () => {
			alive = false;
		};
	}, [debounced]);

	const items = useMemo(() => {
		if (!results) return [];
		const out = [];
		(results.bookings || []).forEach((b) =>
			out.push({
				key: `b${b.id}`,
				group: __('Bookings', 'pointly-booking'),
				icon: 'clipboard-list',
				title: sprintf(/* translators: 1: booking number, 2: customer name. */ __('#%1$d · %2$s', 'pointly-booking'), b.id, b.customer_name || '—'),
				sub: `${b.service_name || ''} · ${formatWhen(b.start)}`,
				onSelect: () => openBooking({ id: b.id }),
			})
		);
		(results.customers || []).forEach((c) =>
			out.push({ key: `c${c.id}`, group: __('Customers', 'pointly-booking'), icon: 'user', title: c.name || c.email, sub: c.email, href: adminUrl('pointlybooking_customers_edit', { id: c.id }) })
		);
		(results.services || []).forEach((s) =>
			out.push({ key: `s${s.id}`, group: __('Services', 'pointly-booking'), icon: 'briefcase', title: s.name, sub: '', href: adminUrl('pointlybooking_services_edit', { id: s.id }) })
		);
		return out;
	}, [results, openBooking]);

	const choose = (item) => {
		setOpen(false);
		setQ('');
		if (item.onSelect) item.onSelect();
		else if (item.href) window.location.href = item.href;
	};

	const onKeyDown = (e) => {
		if (e.key === 'ArrowDown') {
			e.preventDefault();
			setOpen(true);
			setActive((a) => Math.min(items.length - 1, a + 1));
		} else if (e.key === 'ArrowUp') {
			e.preventDefault();
			setActive((a) => Math.max(0, a - 1));
		} else if (e.key === 'Enter' && open && items[active]) {
			e.preventDefault();
			choose(items[active]);
		}
	};

	let lastGroup = '';
	const showPanel = open && q.trim().length >= 2;

	return (
		<div className="bp-gsearch" ref={rootRef}>
			<div className="bp-input-wrap">
				<Icon name="search" className="bp-input-wrap__icon" />
				<input
					ref={inputRef}
					className="bp-input bp-gsearch__input"
					type="search"
					role="combobox"
					aria-expanded={showPanel ? 'true' : 'false'}
					aria-controls={listId}
					aria-autocomplete="list"
					aria-activedescendant={showPanel && items[active] ? `${listId}-${active}` : undefined}
					aria-label={__('Search bookings, customers and services', 'pointly-booking')}
					placeholder={__('Search… ( / )', 'pointly-booking')}
					value={q}
					autoComplete="off"
					onChange={(e) => {
						setQ(e.target.value);
						setOpen(true);
					}}
					onFocus={() => setOpen(true)}
					onKeyDown={onKeyDown}
				/>
				{loading ? (
					<div className="bp-input-wrap__end">
						<Spinner label={__('Searching…', 'pointly-booking')} />
					</div>
				) : null}
			</div>
			{showPanel ? (
				<div className="bp-gsearch__panel bp-popover" id={listId} role="listbox" aria-label={__('Search results', 'pointly-booking')}>
					{error ? <div className="bp-listbox__empty bp-text-danger">{error}</div> : null}
					{!error && !loading && items.length === 0 ? <div className="bp-listbox__empty">{__('No results', 'pointly-booking')}</div> : null}
					{items.map((it, i) => {
						const header = it.group !== lastGroup ? it.group : null;
						lastGroup = it.group;
						return (
							<React.Fragment key={it.key}>
								{header ? <div className="bp-menu__label">{header}</div> : null}
								<div
									id={`${listId}-${i}`}
									role="option"
									aria-selected={i === active ? 'true' : 'false'}
									className={['bp-option', i === active ? 'is-active' : ''].filter(Boolean).join(' ')}
									onMouseEnter={() => setActive(i)}
									onMouseDown={(e) => e.preventDefault()}
									onClick={() => choose(it)}
								>
									<Icon name={it.icon} />
									<span className="bp-gsearch__text">
										<span className="bp-gsearch__title">{it.title}</span>
										{it.sub ? <span className="bp-gsearch__sub">{it.sub}</span> : null}
									</span>
								</div>
							</React.Fragment>
						);
					})}
				</div>
			) : null}
		</div>
	);
}
