#!/usr/bin/env node
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { Box, Text, useApp, useInput } from "ink";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";

//#region src/ui/init/components/shared/TextInput.tsx
/**
* TextInput - Single-line text input component.
*
* A styled text input with cursor, placeholder, and validation support.
*/
/**
* TextInput component for single-line text entry.
*/
function TextInput({ value, onChange, onSubmit, placeholder = "", isFocused = true, mask = false, validate, label }) {
	const [cursorPosition, setCursorPosition] = useState(value.length);
	const [error, setError] = useState(null);
	useEffect(() => {
		if (validate) setError(validate(value));
	}, [value, validate]);
	useEffect(() => {
		if (cursorPosition > value.length) setCursorPosition(value.length);
	}, [value, cursorPosition]);
	useInput((input, key) => {
		if (!isFocused) return;
		if (key.return) {
			if (!error && onSubmit) onSubmit(value);
			return;
		}
		if (key.backspace) {
			if (cursorPosition > 0) {
				onChange(value.slice(0, cursorPosition - 1) + value.slice(cursorPosition));
				setCursorPosition(cursorPosition - 1);
			}
			return;
		}
		if (key.delete) {
			if (cursorPosition < value.length) onChange(value.slice(0, cursorPosition) + value.slice(cursorPosition + 1));
			return;
		}
		if (key.leftArrow) {
			setCursorPosition(Math.max(0, cursorPosition - 1));
			return;
		}
		if (key.rightArrow) {
			setCursorPosition(Math.min(value.length, cursorPosition + 1));
			return;
		}
		if (key.ctrl && input === "a") {
			setCursorPosition(0);
			return;
		}
		if (key.ctrl && input === "e") {
			setCursorPosition(value.length);
			return;
		}
		if (key.ctrl && input === "u") {
			onChange("");
			setCursorPosition(0);
			return;
		}
		if (input && !key.ctrl && !key.meta) {
			onChange(value.slice(0, cursorPosition) + input + value.slice(cursorPosition));
			setCursorPosition(cursorPosition + input.length);
			return;
		}
	}, { isActive: isFocused });
	const displayValue = mask ? "*".repeat(value.length) : value;
	const beforeCursor = displayValue.slice(0, cursorPosition);
	const afterCursor = displayValue.slice(cursorPosition);
	const showPlaceholder = value.length === 0 && placeholder;
	return /* @__PURE__ */ jsxs(Box, {
		flexDirection: "column",
		children: [
			label && /* @__PURE__ */ jsx(Box, {
				marginBottom: 1,
				children: /* @__PURE__ */ jsx(Text, {
					bold: true,
					children: label
				})
			}),
			/* @__PURE__ */ jsx(Box, { children: showPlaceholder ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Text, {
				color: "gray",
				children: "█"
			}), /* @__PURE__ */ jsx(Text, {
				dimColor: true,
				children: placeholder
			})] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
				/* @__PURE__ */ jsx(Text, { children: beforeCursor }),
				/* @__PURE__ */ jsx(Text, {
					color: "gray",
					children: "█"
				}),
				/* @__PURE__ */ jsx(Text, { children: afterCursor })
			] }) }),
			error && /* @__PURE__ */ jsx(Box, {
				marginTop: 1,
				children: /* @__PURE__ */ jsxs(Text, {
					color: "red",
					children: ["⚠ ", error]
				})
			})
		]
	});
}

//#endregion
//#region src/ui/list/ListApp.tsx
/**
* ListApp - Interactive UI for browsing evals, prompts, and datasets.
*
* Provides keyboard navigation, search, and filtering capabilities.
*/
function truncate(str, length) {
	if (str.length <= length) return str;
	return str.slice(0, length - 1) + "…";
}
function formatDate(date) {
	const diff = (/* @__PURE__ */ new Date()).getTime() - date.getTime();
	const days = Math.floor(diff / (1e3 * 60 * 60 * 24));
	if (days === 0) return "today";
	if (days === 1) return "yesterday";
	if (days < 7) return `${days}d ago`;
	if (days < 30) return `${Math.floor(days / 7)}w ago`;
	return `${Math.floor(days / 30)}mo ago`;
}
function EvalRow({ item, isSelected, width }) {
	const fixedWidth = 56 + (item.isRedteam ? 8 : 0);
	const descWidth = Math.max(15, width - fixedWidth);
	const total = (item.passCount ?? 0) + (item.failCount ?? 0) + (item.errorCount ?? 0);
	const hasResults = total > 0;
	const passRate = hasResults ? Math.round((item.passCount ?? 0) / total * 100) : null;
	return /* @__PURE__ */ jsxs(Box, { children: [
		/* @__PURE__ */ jsx(Box, {
			width: 3,
			children: /* @__PURE__ */ jsx(Text, {
				color: isSelected ? "cyan" : void 0,
				children: isSelected ? "▶" : " "
			})
		}),
		/* @__PURE__ */ jsx(Box, {
			width: 20,
			children: /* @__PURE__ */ jsx(Text, {
				color: isSelected ? "cyan" : "yellow",
				children: truncate(item.id, 18)
			})
		}),
		/* @__PURE__ */ jsx(Box, {
			width: descWidth,
			children: /* @__PURE__ */ jsx(Text, {
				color: isSelected ? "white" : "gray",
				children: truncate(item.description || "(no description)", descWidth - 2)
			})
		}),
		/* @__PURE__ */ jsx(Box, {
			width: 15,
			children: hasResults ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(Text, {
				color: passRate !== null && passRate >= 80 ? "green" : passRate !== null && passRate >= 50 ? "yellow" : "red",
				children: [passRate, "%"]
			}), /* @__PURE__ */ jsxs(Text, {
				dimColor: true,
				children: [
					" ",
					"(",
					item.passCount,
					"/",
					total,
					")"
				]
			})] }) : /* @__PURE__ */ jsx(Text, {
				dimColor: true,
				children: "pending"
			})
		}),
		/* @__PURE__ */ jsx(Box, {
			width: 10,
			children: /* @__PURE__ */ jsx(Text, {
				dimColor: true,
				children: formatDate(item.createdAt)
			})
		}),
		item.isRedteam && /* @__PURE__ */ jsx(Box, {
			width: 8,
			children: /* @__PURE__ */ jsx(Text, {
				color: "red",
				children: "redteam"
			})
		})
	] });
}
function PromptRow({ item, isSelected, width }) {
	const promptWidth = Math.max(30, width - 35);
	return /* @__PURE__ */ jsxs(Box, { children: [
		/* @__PURE__ */ jsx(Box, {
			width: 3,
			children: /* @__PURE__ */ jsx(Text, {
				color: isSelected ? "cyan" : void 0,
				children: isSelected ? "▶" : " "
			})
		}),
		/* @__PURE__ */ jsx(Box, {
			width: 10,
			children: /* @__PURE__ */ jsx(Text, {
				color: isSelected ? "cyan" : "yellow",
				children: item.id.slice(0, 8)
			})
		}),
		/* @__PURE__ */ jsx(Box, {
			width: promptWidth,
			children: /* @__PURE__ */ jsx(Text, {
				color: isSelected ? "white" : "gray",
				children: truncate(item.raw.replace(/\n/g, " "), promptWidth - 2)
			})
		}),
		/* @__PURE__ */ jsx(Box, {
			width: 12,
			children: /* @__PURE__ */ jsxs(Text, {
				dimColor: true,
				children: [item.evalCount, " evals"]
			})
		})
	] });
}
function DatasetRow({ item, isSelected, width }) {
	const bestPromptWidth = Math.max(15, width - 50);
	return /* @__PURE__ */ jsxs(Box, { children: [
		/* @__PURE__ */ jsx(Box, {
			width: 3,
			children: /* @__PURE__ */ jsx(Text, {
				color: isSelected ? "cyan" : void 0,
				children: isSelected ? "▶" : " "
			})
		}),
		/* @__PURE__ */ jsx(Box, {
			width: 10,
			children: /* @__PURE__ */ jsx(Text, {
				color: isSelected ? "cyan" : "yellow",
				children: item.id.slice(0, 8)
			})
		}),
		/* @__PURE__ */ jsx(Box, {
			width: 12,
			children: /* @__PURE__ */ jsxs(Text, {
				color: isSelected ? "white" : "gray",
				children: [item.testCount, " tests"]
			})
		}),
		/* @__PURE__ */ jsx(Box, {
			width: 12,
			children: /* @__PURE__ */ jsxs(Text, {
				dimColor: true,
				children: [item.evalCount, " evals"]
			})
		}),
		item.bestPromptId && /* @__PURE__ */ jsx(Box, {
			width: bestPromptWidth,
			children: /* @__PURE__ */ jsxs(Text, {
				dimColor: true,
				children: ["best: ", item.bestPromptId.slice(0, 8)]
			})
		})
	] });
}
function SearchBar({ value, onChange, onSubmit, isActive }) {
	return /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Text, {
		color: isActive ? "cyan" : "gray",
		children: "Search: "
	}), isActive ? /* @__PURE__ */ jsx(TextInput, {
		value,
		onChange,
		onSubmit,
		isFocused: isActive,
		placeholder: "Type to search..."
	}) : /* @__PURE__ */ jsx(Text, {
		color: "gray",
		children: value || "(press / to search)"
	})] });
}
function ListApp({ resourceType, items: initialItems = [], onSelect, onExit, onLoadMore, onSearch, hasMore: initialHasMore = true, pageSize = 50, totalCount: initialTotalCount }) {
	const { exit } = useApp();
	const [items, setItems] = useState(initialItems);
	const [selectedIndex, setSelectedIndex] = useState(0);
	const [searchQuery, setSearchQuery] = useState("");
	const [isSearching, setIsSearching] = useState(false);
	const [loading, setLoading] = useState(false);
	const [loadingMore, setLoadingMore] = useState(false);
	const [hasMore, setHasMore] = useState(initialHasMore);
	const [error, setError] = useState(null);
	const totalCount = initialTotalCount;
	const jumpToEndRef = useRef(false);
	const [terminalWidth] = useState(process.stdout.columns || 80);
	const visibleRows = Math.max(5, (process.stdout.rows || 20) - 10);
	const filteredItems = useMemo(() => {
		if (!searchQuery.trim()) return items;
		const query = searchQuery.toLowerCase();
		return items.filter((item) => {
			if ("description" in item && item.description?.toLowerCase().includes(query)) return true;
			if (item.id.toLowerCase().includes(query)) return true;
			if ("raw" in item && item.raw.toLowerCase().includes(query)) return true;
			if ("vars" in item) {
				const evalItem = item;
				if (evalItem.vars.some((v) => v.toLowerCase().includes(query))) return true;
				if (evalItem.prompts.some((p) => p.toLowerCase().includes(query))) return true;
			}
			return false;
		});
	}, [items, searchQuery]);
	const scrollOffset = useMemo(() => {
		if (selectedIndex < visibleRows / 2) return 0;
		if (selectedIndex > filteredItems.length - visibleRows / 2) return Math.max(0, filteredItems.length - visibleRows);
		return Math.max(0, selectedIndex - Math.floor(visibleRows / 2));
	}, [
		selectedIndex,
		filteredItems.length,
		visibleRows
	]);
	const visibleItems = useMemo(() => {
		return filteredItems.slice(scrollOffset, scrollOffset + visibleRows);
	}, [
		filteredItems,
		scrollOffset,
		visibleRows
	]);
	useEffect(() => {
		if (initialItems.length === 0 && onLoadMore) {
			setLoading(true);
			onLoadMore(0, pageSize).then((data) => {
				setItems(data);
				setHasMore(data.length >= pageSize);
				setLoading(false);
			}).catch((err) => {
				setError(err.message);
				setLoading(false);
			});
		}
	}, [
		initialItems.length,
		onLoadMore,
		pageSize
	]);
	const handleSearch = useCallback(async () => {
		setSelectedIndex(0);
		if (onSearch && searchQuery.trim()) {
			setLoading(true);
			try {
				const results = await onSearch(searchQuery);
				setItems(results);
				setHasMore(results.length >= pageSize);
			} catch (err) {
				setError(err.message);
			} finally {
				setLoading(false);
			}
		}
		setIsSearching(false);
	}, [
		searchQuery,
		onSearch,
		pageSize
	]);
	const handleLoadMore = useCallback(async () => {
		if (!onLoadMore || loadingMore || !hasMore) return;
		setLoadingMore(true);
		try {
			const newItems = await onLoadMore(items.length, pageSize);
			if (newItems.length === 0) setHasMore(false);
			else {
				setItems((prev) => [...prev, ...newItems]);
				setHasMore(newItems.length >= pageSize);
			}
		} catch (err) {
			setError(err.message);
		} finally {
			setLoadingMore(false);
		}
	}, [
		onLoadMore,
		loadingMore,
		hasMore,
		items.length,
		pageSize
	]);
	useEffect(() => {
		if (!jumpToEndRef.current) return;
		if (!hasMore) {
			setSelectedIndex(items.length - 1);
			jumpToEndRef.current = false;
		} else if (!loadingMore && onLoadMore) handleLoadMore();
	}, [
		hasMore,
		loadingMore,
		items.length,
		onLoadMore,
		handleLoadMore
	]);
	const navigateDown = useCallback((amount) => {
		setSelectedIndex((prev) => {
			const newIndex = Math.min(filteredItems.length - 1, prev + amount);
			if (hasMore && !searchQuery.trim() && newIndex >= items.length - 5) handleLoadMore();
			return newIndex;
		});
	}, [
		filteredItems.length,
		hasMore,
		searchQuery,
		items.length,
		handleLoadMore
	]);
	useInput((input, key) => {
		if (isSearching) {
			if (key.escape) {
				setIsSearching(false);
				setSearchQuery("");
			}
			return;
		}
		const halfPage = Math.floor(visibleRows / 2);
		const cancelJumpToEnd = () => {
			jumpToEndRef.current = false;
		};
		if (key.upArrow || input === "k") {
			cancelJumpToEnd();
			setSelectedIndex((prev) => Math.max(0, prev - 1));
		} else if (key.downArrow || input === "j") {
			cancelJumpToEnd();
			navigateDown(1);
		} else if (key.pageUp || key.ctrl && input === "b") {
			cancelJumpToEnd();
			setSelectedIndex((prev) => Math.max(0, prev - visibleRows));
		} else if (key.pageDown || key.ctrl && input === "f") {
			cancelJumpToEnd();
			navigateDown(visibleRows);
		} else if (key.ctrl && input === "u") {
			cancelJumpToEnd();
			setSelectedIndex((prev) => Math.max(0, prev - halfPage));
		} else if (key.ctrl && input === "d") {
			cancelJumpToEnd();
			navigateDown(halfPage);
		} else if (key.ctrl && input === "e") {
			cancelJumpToEnd();
			navigateDown(1);
		} else if (key.ctrl && input === "y") {
			cancelJumpToEnd();
			setSelectedIndex((prev) => Math.max(0, prev - 1));
		} else if (input === "g") {
			setSelectedIndex(0);
			jumpToEndRef.current = false;
		} else if (input === "G") if (hasMore && !searchQuery.trim()) {
			jumpToEndRef.current = true;
			handleLoadMore();
		} else setSelectedIndex(filteredItems.length - 1);
		if (key.return && filteredItems[selectedIndex]) onSelect?.(filteredItems[selectedIndex]);
		else if (input === "/") setIsSearching(true);
		else if (input === "q" || key.escape) {
			onExit?.();
			exit();
		} else if (input === "r") {
			if (onLoadMore) {
				setLoading(true);
				onLoadMore(0, pageSize).then((data) => {
					setItems(data);
					setSelectedIndex(0);
					setHasMore(data.length >= pageSize);
					setLoading(false);
				}).catch((err) => {
					setError(err.message);
					setLoading(false);
				});
			}
		}
	});
	const resourceLabels = {
		evals: "Evaluations",
		prompts: "Prompts",
		datasets: "Datasets"
	};
	const renderItem = (item, index) => {
		const isSelected = index + scrollOffset === selectedIndex;
		const key = "id" in item ? item.id : String(index);
		if (resourceType === "evals") return /* @__PURE__ */ jsx(EvalRow, {
			item,
			isSelected,
			width: terminalWidth
		}, key);
		else if (resourceType === "prompts") return /* @__PURE__ */ jsx(PromptRow, {
			item,
			isSelected,
			width: terminalWidth
		}, key);
		else return /* @__PURE__ */ jsx(DatasetRow, {
			item,
			isSelected,
			width: terminalWidth
		}, key);
	};
	return /* @__PURE__ */ jsxs(Box, {
		flexDirection: "column",
		padding: 1,
		children: [
			/* @__PURE__ */ jsxs(Box, {
				marginBottom: 1,
				children: [
					/* @__PURE__ */ jsx(Text, {
						bold: true,
						color: "cyan",
						children: resourceLabels[resourceType]
					}),
					/* @__PURE__ */ jsx(Text, { children: " " }),
					/* @__PURE__ */ jsxs(Text, {
						dimColor: true,
						children: [
							"(",
							searchQuery.trim() ? `${filteredItems.length} filtered` : `${items.length} loaded`,
							totalCount && !searchQuery.trim() ? ` of ${totalCount} total` : "",
							loading ? ", loading..." : "",
							")"
						]
					})
				]
			}),
			/* @__PURE__ */ jsx(Box, {
				marginBottom: 1,
				children: /* @__PURE__ */ jsx(SearchBar, {
					value: searchQuery,
					onChange: setSearchQuery,
					onSubmit: handleSearch,
					isActive: isSearching
				})
			}),
			error && /* @__PURE__ */ jsx(Box, {
				marginBottom: 1,
				children: /* @__PURE__ */ jsxs(Text, {
					color: "red",
					children: ["Error: ", error]
				})
			}),
			/* @__PURE__ */ jsx(Box, {
				flexDirection: "column",
				height: visibleRows,
				children: loading && items.length === 0 ? /* @__PURE__ */ jsx(Text, {
					color: "gray",
					children: "Loading..."
				}) : filteredItems.length === 0 ? /* @__PURE__ */ jsx(Text, {
					color: "gray",
					children: searchQuery.trim() ? "No matches found" : "No items found"
				}) : visibleItems.map((item, index) => renderItem(item, index))
			}),
			filteredItems.length > visibleRows && /* @__PURE__ */ jsxs(Box, {
				marginTop: 1,
				children: [/* @__PURE__ */ jsxs(Text, {
					dimColor: true,
					children: [
						"Showing ",
						scrollOffset + 1,
						"-",
						Math.min(scrollOffset + visibleRows, filteredItems.length),
						totalCount && !searchQuery.trim() ? ` of ${totalCount}` : ` of ${filteredItems.length}`
					]
				}), loadingMore && /* @__PURE__ */ jsx(Text, {
					color: "yellow",
					children: " Loading..."
				})]
			}),
			/* @__PURE__ */ jsxs(Box, {
				marginTop: 1,
				flexDirection: "column",
				children: [/* @__PURE__ */ jsx(Text, {
					dimColor: true,
					children: "↑↓/jk: navigate | ^d/^u: half page | ^f/^b: full page | g/G: start/end"
				}), /* @__PURE__ */ jsx(Text, {
					dimColor: true,
					children: "Enter: select | /: search | r: refresh | q: quit"
				})]
			})
		]
	});
}

//#endregion
export { ListApp };
//# sourceMappingURL=ListApp-B8H3BeH6.js.map