import React, { useEffect, useMemo, useState } from 'react';
import { __, _n, sprintf } from '@wordpress/i18n';
import { Alert, Button, DataTable, DropdownMenu, EmptyState, IconButton, Input, Pagination, Select, useConfirm, useToast } from '../../shared/ui';
import useAsync from '../core/useAsync';
import { Page, PageHeader } from '../ui/page';

const PER_PAGE = 20;

/**
 * Standard admin list screen: search, optional filters, sortable table, pagination,
 * row actions with confirmation, empty states and loading skeletons.
 *
 * Data is loaded once and filtered/sorted in the browser (catalog-sized lists).
 *
 * @param {Object}   props
 * @param {string}   props.title
 * @param {string}   [props.subtitle]
 * @param {Function} props.load                 () => Promise<Array>
 * @param {Array}    props.columns              DataTable columns; `sortValue(row)` enables sorting on the client.
 * @param {Function} [props.rowKey]
 * @param {Function} [props.editHref]           (row) => URL (row click + "Edit" action)
 * @param {string}   [props.addHref]
 * @param {string}   [props.addLabel]
 * @param {Function} [props.searchText]         (row) => string searched by the box
 * @param {Array}    [props.filters]            [{ key, label, options:[{value,label}], test:(row,value)=>bool }]
 * @param {Function} [props.onDelete]           async (row) => void
 * @param {Function} [props.deleteMessage]      (row) => string
 * @param {Function} [props.rowActions]         (row) => extra menu items
 * @param {Object}   [props.empty]              { icon, title, text }
 * @param {*}        [props.headerActions]
 * @param {Function} [props.getName]            (row) => label used in confirmations
 */
export default function ResourceList({
	title,
	subtitle,
	load,
	columns,
	rowKey = (r) => r.id,
	editHref,
	addHref,
	addLabel,
	searchText,
	searchPlaceholder,
	filters = [],
	onDelete,
	deleteMessage,
	rowActions,
	empty = {},
	headerActions,
	getName = (r) => r.name || `#${r.id}`,
	initialSort,
	children,
}) {
	const toast = useToast();
	const confirm = useConfirm();
	const list = useAsync(load, []);
	const [q, setQ] = useState('');
	const [filterValues, setFilterValues] = useState({});
	const [sort, setSort] = useState(initialSort || null);
	const [page, setPage] = useState(1);

	const rows = useMemo(() => (Array.isArray(list.data) ? list.data : list.data && Array.isArray(list.data.items) ? list.data.items : []), [list.data]);

	const filtered = useMemo(() => {
		const needle = q.trim().toLowerCase();
		let out = rows.filter((r) => (!needle || !searchText ? true : String(searchText(r) || '').toLowerCase().includes(needle)));
		filters.forEach((f) => {
			const v = filterValues[f.key];
			if (v !== undefined && v !== '' && v !== 'all') out = out.filter((r) => f.test(r, v));
		});
		if (sort) {
			const col = columns.find((c) => c.key === sort.key);
			if (col && col.sortValue) {
				out = [...out].sort((a, b) => {
					const av = col.sortValue(a);
					const bv = col.sortValue(b);
					const cmp = typeof av === 'number' && typeof bv === 'number' ? av - bv : String(av ?? '').localeCompare(String(bv ?? ''), undefined, { numeric: true, sensitivity: 'base' });
					return sort.dir === 'asc' ? cmp : -cmp;
				});
			}
		}
		return out;
	}, [rows, q, filterValues, sort, columns, filters, searchText]);

	useEffect(() => setPage(1), [q, filterValues, sort]);
	const pageRows = filtered.slice((page - 1) * PER_PAGE, page * PER_PAGE);
	const hasFilters = !!q.trim() || Object.values(filterValues).some((v) => v && v !== 'all');

	const remove = async (row) => {
		const name = getName(row);
		const ok = await confirm({
			title: sprintf(/* translators: %s: item name. */ __('Delete “%s”?', 'pointly-booking'), name),
			message: deleteMessage ? deleteMessage(row) : __('This cannot be undone.', 'pointly-booking'),
			confirmLabel: __('Delete', 'pointly-booking'),
			cancelLabel: __('Keep it', 'pointly-booking'),
			danger: true,
		});
		if (!ok) return;
		try {
			await onDelete(row);
			toast.success(sprintf(/* translators: %s: item name. */ __('“%s” deleted', 'pointly-booking'), name));
			list.reload();
		} catch (e) {
			toast.error(__('Could not delete', 'pointly-booking'), e.message);
		}
	};

	const cols = useMemo(() => {
		const withActions = [...columns];
		if (editHref || onDelete || rowActions) {
			withActions.push({
				key: 'actions',
				header: <span className="bp-visually-hidden">{__('Actions', 'pointly-booking')}</span>,
				width: '56px',
				render: (row) => (
					<DropdownMenu
						label={sprintf(/* translators: %s: item name. */ __('Actions for %s', 'pointly-booking'), getName(row))}
						items={[
							...(editHref ? [{ label: __('Edit', 'pointly-booking'), icon: 'pencil', href: editHref(row) }] : []),
							...(rowActions ? rowActions(row) : []),
							...(onDelete ? [{ separator: true }, { label: __('Delete', 'pointly-booking'), icon: 'trash', danger: true, onSelect: () => remove(row) }] : []),
						]}
						trigger={({ ref, props }) => (
							<IconButton ref={ref} icon="more-horizontal" variant="ghost" size="sm" label={sprintf(/* translators: %s: item name. */ __('Actions for %s', 'pointly-booking'), getName(row))} {...props} />
						)}
					/>
				),
			});
		}
		return withActions.map((c) => ({ ...c, sortable: !!c.sortValue }));
	}, [columns, editHref, onDelete, rowActions]); // eslint-disable-line react-hooks/exhaustive-deps

	const loading = list.loading && !list.data;
	const nothingYet = !loading && rows.length === 0 && !list.error;

	return (
		<Page>
			<PageHeader
				title={title}
				subtitle={subtitle}
				actions={
					<>
						{headerActions}
						{addHref ? (
							<Button variant="primary" icon="plus" href={addHref}>
								{addLabel || __('Add new', 'pointly-booking')}
							</Button>
						) : null}
					</>
				}
			/>

			{children}

			{list.error && !list.data ? (
				<Alert tone="danger" title={__('This could not be loaded', 'pointly-booking')} actions={<Button size="sm" variant="secondary" onClick={list.reload}>{__('Try again', 'pointly-booking')}</Button>}>
					{list.error}
				</Alert>
			) : null}

			{!nothingYet && (searchText || filters.length) ? (
				<div className="bp-list__filters bp-list__filters--compact" role="search">
					{searchText ? (
						<div className="bp-list__search">
							<Input icon="search" type="search" placeholder={searchPlaceholder || __('Search…', 'pointly-booking')} value={q} onChange={(e) => setQ(e.target.value)} aria-label={__('Search', 'pointly-booking')} />
						</div>
					) : null}
					{filters.map((f) => (
						<Select key={f.key} aria-label={f.label} value={filterValues[f.key] || ''} placeholder={f.label} options={f.options} onChange={(e) => setFilterValues((v) => ({ ...v, [f.key]: e.target.value }))} />
					))}
					{hasFilters ? (
						<Button variant="ghost" icon="x" onClick={() => { setQ(''); setFilterValues({}); }}>
							{__('Clear', 'pointly-booking')}
						</Button>
					) : null}
				</div>
			) : null}

			<DataTable
				caption={title}
				columns={cols}
				rows={pageRows}
				rowKey={rowKey}
				loading={loading}
				sort={sort}
				onSortChange={setSort}
				onRowClick={editHref ? (row) => { window.location.href = editHref(row); } : undefined}
				empty={
					nothingYet ? (
						<EmptyState
							icon={empty.icon || 'sparkles'}
							title={empty.title || __('Nothing here yet', 'pointly-booking')}
							actions={addHref ? <Button variant="primary" icon="plus" href={addHref}>{empty.cta || addLabel || __('Add the first one', 'pointly-booking')}</Button> : null}
						>
							{empty.text}
						</EmptyState>
					) : (
						<EmptyState
							icon="search"
							title={__('No results', 'pointly-booking')}
							actions={<Button variant="secondary" onClick={() => { setQ(''); setFilterValues({}); }}>{__('Clear filters', 'pointly-booking')}</Button>}
						>
							{__('Try a different search or filter.', 'pointly-booking')}
						</EmptyState>
					)
				}
			/>

			{filtered.length > PER_PAGE ? <Pagination page={page} perPage={PER_PAGE} total={filtered.length} onPageChange={setPage} /> : null}
			{!loading && rows.length > 0 ? (
				<p className="bp-text-subtle bp-text-sm" aria-live="polite">
					{sprintf(_n('%d item', '%d items', filtered.length, 'pointly-booking'), filtered.length)}
					{hasFilters ? sprintf(/* translators: %d: total number of items. */ __('(of %d)', 'pointly-booking'), rows.length) : ''}
				</p>
			) : null}
		</Page>
	);
}
