import { cn } from "./cva.js";
import { Button } from "./Button.js";
import { Input } from "./Input.js";
import { ErrorState } from "./ErrorState.js";
import { Table } from "./Table.js";
import { Skeleton } from "./Skeleton.js";
import { Pagination } from "./Pagination.js";
import * as React from "react";
import { jsx, jsxs } from "react/jsx-runtime";
//#region src/DataTable.tsx
function withSorting(options = {}) {
	return {
		kind: "sorting",
		options
	};
}
function withSearch(options = {}) {
	return {
		kind: "search",
		options
	};
}
function withColumnResizing(options = {}) {
	return {
		kind: "resizing",
		options
	};
}
function withPagination(options) {
	return {
		kind: "pagination",
		options
	};
}
const MIN_WIDTH_DEFAULT = 48;
const KEYBOARD_RESIZE_STEP = 16;
function useControllableState(controlled, defaultValue, onChange) {
	const [internal, setInternal] = React.useState(defaultValue);
	return [controlled !== void 0 ? controlled : internal, React.useCallback((next) => {
		if (controlled === void 0) setInternal(next);
		onChange?.(next);
	}, [controlled, onChange])];
}
function pickCapability(capabilities, kind) {
	if (!capabilities) return void 0;
	for (let i = capabilities.length - 1; i >= 0; i--) {
		const capability = capabilities[i];
		if (capability?.kind === kind && "options" in capability) return capability.options;
	}
}
function accessorValue(row, column) {
	return row[column.id];
}
function defaultCell(row, column) {
	const value = accessorValue(row, column);
	return value === null || value === void 0 ? "" : String(value);
}
function sortKey(row, column) {
	if (column.sortValue) return column.sortValue(row);
	const value = accessorValue(row, column);
	if (value === null || value === void 0) return null;
	return typeof value === "number" ? value : String(value);
}
function searchKey(row, column) {
	if (column.searchValue) return column.searchValue(row);
	const value = accessorValue(row, column);
	return value === null || value === void 0 ? "" : String(value);
}
function compareKeys(a, b) {
	if (typeof a === "number" && typeof b === "number") return a - b;
	return String(a).localeCompare(String(b));
}
function ResizeHandle({ columnLabel, width, minWidth, onResize }) {
	const dragOrigin = React.useRef(null);
	return /* @__PURE__ */ jsx("span", {
		role: "separator",
		"aria-orientation": "vertical",
		"aria-label": `Resize ${columnLabel} column`,
		"aria-valuenow": Math.round(width),
		"aria-valuemin": minWidth,
		tabIndex: 0,
		className: "absolute inset-y-0 right-0 w-2 cursor-col-resize touch-none select-none focus-visible:outline focus-visible:outline-accent",
		onKeyDown: (event) => {
			if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
				event.preventDefault();
				const delta = event.key === "ArrowRight" ? KEYBOARD_RESIZE_STEP : -16;
				onResize(Math.max(minWidth, width + delta));
			}
		},
		onPointerDown: (event) => {
			event.preventDefault();
			dragOrigin.current = {
				pointerX: event.clientX,
				startWidth: width
			};
			event.currentTarget.setPointerCapture(event.pointerId);
		},
		onPointerMove: (event) => {
			if (!dragOrigin.current) return;
			const next = dragOrigin.current.startWidth + (event.clientX - dragOrigin.current.pointerX);
			onResize(Math.max(minWidth, next));
		},
		onPointerUp: (event) => {
			dragOrigin.current = null;
			event.currentTarget.releasePointerCapture(event.pointerId);
		}
	});
}
function DataTable({ caption, columns, rows, getRowId, capabilities, loading = false, error = null, onRetry, emptyState = "No results.", className }) {
	const searchId = React.useId();
	const sorting = pickCapability(capabilities, "sorting");
	const search = pickCapability(capabilities, "search");
	const resizing = pickCapability(capabilities, "resizing");
	const pagination = pickCapability(capabilities, "pagination");
	const [sort, setSort] = useControllableState(sorting?.sort, sorting?.defaultSort ?? null, sorting?.onSortChange);
	const [query, setQuery] = useControllableState(search?.query, search?.defaultQuery ?? "", search?.onQueryChange);
	const [page, setPage] = useControllableState(pagination?.page, pagination?.defaultPage ?? 1, pagination?.onPageChange);
	const [widths, setWidths] = useControllableState(resizing?.widths, resizing?.defaultWidths ?? {}, resizing?.onWidthsChange);
	const filtered = React.useMemo(() => {
		if (!search || search.manual || query.trim() === "") return rows;
		const needle = query.trim().toLowerCase();
		return rows.filter((row) => columns.some((column) => searchKey(row, column).toLowerCase().includes(needle)));
	}, [
		rows,
		columns,
		query,
		search
	]);
	const sorted = React.useMemo(() => {
		if (!sorting || sorting.manual || !sort) return filtered;
		const column = columns.find((c) => c.id === sort.columnId);
		if (!column) return filtered;
		const direction = sort.direction === "asc" ? 1 : -1;
		return filtered.map((row, index) => ({
			row,
			index
		})).sort((a, b) => {
			const keyA = sortKey(a.row, column);
			const keyB = sortKey(b.row, column);
			if (keyA === null || keyB === null) {
				if (keyA === null && keyB === null) return a.index - b.index;
				return keyA === null ? 1 : -1;
			}
			const order = compareKeys(keyA, keyB);
			return order !== 0 ? order * direction : a.index - b.index;
		}).map((entry) => entry.row);
	}, [
		filtered,
		columns,
		sort,
		sorting
	]);
	const clientPaginated = pagination !== void 0 && !pagination.manual && pagination.pageSize !== void 0;
	const pageCount = pagination?.manual ? pagination.pageCount : clientPaginated && pagination?.pageSize !== void 0 ? Math.max(1, Math.ceil(sorted.length / pagination.pageSize)) : 1;
	const effectivePage = clientPaginated ? Math.min(page, pageCount) : page;
	const paginated = React.useMemo(() => {
		if (!clientPaginated || pagination?.pageSize === void 0) return sorted;
		return sorted.slice((effectivePage - 1) * pagination.pageSize, effectivePage * pagination.pageSize);
	}, [
		sorted,
		effectivePage,
		clientPaginated,
		pagination?.pageSize
	]);
	const showPagination = pagination !== void 0 && (pagination.manual === true || pageCount > 1);
	function resetToFirstPage() {
		if (clientPaginated) setPage(1);
	}
	function cycleSort(columnId) {
		if (!sort || sort.columnId !== columnId) setSort({
			columnId,
			direction: "asc"
		});
		else setSort(sort.direction === "asc" ? {
			columnId,
			direction: "desc"
		} : null);
		resetToFirstPage();
	}
	function updateQuery(next) {
		setQuery(next);
		resetToFirstPage();
	}
	const anyWidth = resizing !== void 0 && columns.some((column) => widths[column.id] !== void 0 || column.width !== void 0);
	function columnLabel(column) {
		return typeof column.header === "string" ? column.header : column.id;
	}
	return /* @__PURE__ */ jsxs("div", {
		className: cn("flex flex-col gap-3", className),
		"aria-busy": loading || void 0,
		children: [
			search ? /* @__PURE__ */ jsxs("div", {
				className: "flex flex-col gap-1",
				children: [/* @__PURE__ */ jsx("label", {
					htmlFor: searchId,
					className: "text-sm font-semibold text-fg",
					children: search.label ?? "Search"
				}), /* @__PURE__ */ jsx(Input, {
					id: searchId,
					type: "search",
					size: "sm",
					value: query,
					onChange: (event) => updateQuery(event.currentTarget.value)
				})]
			}) : null,
			search ? /* @__PURE__ */ jsx("p", {
				role: "status",
				"aria-live": "polite",
				className: "sr-only",
				children: loading || error ? "" : `${sorted.length} results`
			}) : null,
			error ? /* @__PURE__ */ jsx(ErrorState, {
				variant: "inline",
				title: "Data couldn't load",
				message: error,
				action: onRetry ? /* @__PURE__ */ jsx(Button, {
					tone: "surface",
					radius: "sm",
					size: "sm",
					type: "button",
					onClick: onRetry,
					children: "Try again"
				}) : void 0
			}) : loading ? /* @__PURE__ */ jsxs("div", {
				className: "flex flex-col gap-2",
				"aria-hidden": "true",
				children: [/* @__PURE__ */ jsx(Skeleton, { variant: "block" }), /* @__PURE__ */ jsx(Skeleton, { variant: "block" })]
			}) : paginated.length === 0 ? /* @__PURE__ */ jsx("div", {
				className: "text-sm text-fg-muted",
				children: emptyState
			}) : /* @__PURE__ */ jsx("div", {
				className: "overflow-x-auto",
				children: /* @__PURE__ */ jsxs(Table, {
					caption,
					className: anyWidth ? "table-fixed" : void 0,
					children: [
						anyWidth ? /* @__PURE__ */ jsx("colgroup", { children: columns.map((column) => {
							const width = widths[column.id] ?? column.width;
							return /* @__PURE__ */ jsx("col", { style: width !== void 0 ? { width: `${width}px` } : void 0 }, column.id);
						}) }) : null,
						/* @__PURE__ */ jsx(Table.Head, { children: /* @__PURE__ */ jsx(Table.Row, { children: columns.map((column) => {
							const sortEnabled = sorting !== void 0 && column.sortable === true;
							const isSorted = sort?.columnId === column.id;
							const resizeEnabled = resizing !== void 0 && column.resizable === true;
							const width = widths[column.id] ?? column.width ?? 0;
							return /* @__PURE__ */ jsxs(Table.Th, {
								scope: "col",
								className: resizeEnabled ? "relative" : void 0,
								sort: sortEnabled ? isSorted && sort ? sort.direction : "none" : void 0,
								onSort: sortEnabled ? () => cycleSort(column.id) : void 0,
								children: [column.header, resizeEnabled ? /* @__PURE__ */ jsx(ResizeHandle, {
									columnLabel: columnLabel(column),
									width: width || (column.minWidth ?? MIN_WIDTH_DEFAULT),
									minWidth: column.minWidth ?? MIN_WIDTH_DEFAULT,
									onResize: (next) => setWidths({
										...widths,
										[column.id]: next
									})
								}) : null]
							}, column.id);
						}) }) }),
						/* @__PURE__ */ jsx(Table.Body, { children: paginated.map((row) => /* @__PURE__ */ jsx(Table.Row, { children: columns.map((column) => /* @__PURE__ */ jsx(Table.Td, { children: column.cell ? column.cell(row) : defaultCell(row, column) }, column.id)) }, getRowId(row))) })
					]
				})
			}),
			!error && !loading && showPagination ? /* @__PURE__ */ jsx(Pagination, {
				page: effectivePage,
				pageCount,
				onPageChange: setPage,
				label: pagination?.label ?? `${caption} pagination`
			}) : null
		]
	});
}
//#endregion
export { DataTable, withColumnResizing, withPagination, withSearch, withSorting };
