import { getLocalizedString } from "@olenbetong/appframe-core";
import { Fragment, type RefObject } from "react";

import { AppMenuColorScheme } from "./AppMenuColorScheme.js";
import { countItems, groupLabel, type Selection, toRailSections } from "./menuEntries.js";
import type { AppMenuCategory } from "./types.js";
import { useRovingTabIndex } from "./useRovingTabIndex.js";

export type AppMenuRailProps = {
	searchRef: RefObject<HTMLInputElement | null>;
	search: string;
	onSearchChange: (value: string) => void;
	/** App groups, in the order they are listed. */
	groups: { key: string; count: number }[];
	/** Number of apps matching the search, shown next to "All applications". */
	appCount: number;
	/** Extra link categories, listed after the app groups. */
	categories: AppMenuCategory[];
	selection: Selection;
	onSelect: (selection: Selection) => void;
};

/**
 * The app menu's left rail: the local search field, the app groups and any
 * extra link categories.
 *
 * The rail is a single tab stop; the arrow keys move focus between the buttons.
 */
export function AppMenuRail({
	searchRef,
	search,
	onSearchChange,
	groups,
	appCount,
	categories,
	selection,
	onSelect,
}: AppMenuRailProps) {
	// "All applications", then the app groups, then the categories.
	let roving = useRovingTabIndex(groups.length + 1 + categories.length);
	let railSections = toRailSections(categories);
	let categoryIndex = groups.length;

	function isSelected(next: NonNullable<Selection>) {
		if (selection === null) return false;
		if (next.type === "group") return selection.type === "group" && selection.key === next.key;
		return selection.type === "category" && selection.id === next.id;
	}

	return (
		<div className="ob-app-menu__rail">
			<div className="ds-search ob-app-menu__search" data-size="sm">
				<input
					ref={searchRef}
					className="ds-input"
					type="search"
					value={search}
					onChange={(event) => onSearchChange(event.target.value)}
					placeholder={getLocalizedString("Search applications")}
					aria-label={getLocalizedString("Search applications")}
					autoComplete="off"
				/>
			</div>

			<nav className="ob-app-menu__groups" aria-label={getLocalizedString("Categories")} onKeyDown={roving.onKeyDown}>
				<button
					type="button"
					className="ob-app-menu__group-button"
					aria-current={selection === null ? "true" : undefined}
					onClick={() => onSelect(null)}
					{...roving.getItemProps(0)}
				>
					<span>{getLocalizedString("All applications")}</span>
					<span className="ob-app-menu__count">{appCount}</span>
				</button>
				{groups.map(({ key, count }, index) => (
					<button
						key={key}
						type="button"
						className="ob-app-menu__group-button"
						aria-current={isSelected({ type: "group", key }) ? "true" : undefined}
						onClick={() => onSelect({ type: "group", key })}
						{...roving.getItemProps(index + 1)}
					>
						<span>{groupLabel(key)}</span>
						<span className="ob-app-menu__count">{count}</span>
					</button>
				))}

				{railSections.map(([section, sectionCategories]) => (
					<Fragment key={section || "\u0000default"}>
						{section && <h2 className="ob-app-menu__rail-heading">{section}</h2>}
						{sectionCategories.map((category) => {
							categoryIndex += 1;
							let railIndex = categoryIndex;
							return (
								<button
									key={category.id}
									type="button"
									className="ob-app-menu__group-button"
									aria-current={isSelected({ type: "category", id: category.id }) ? "true" : undefined}
									onClick={() => onSelect({ type: "category", id: category.id })}
									{...roving.getItemProps(railIndex)}
								>
									<span>{category.label}</span>
									<span className="ob-app-menu__count">{countItems(category)}</span>
								</button>
							);
						})}
					</Fragment>
				))}
			</nav>

			<AppMenuColorScheme />
		</div>
	);
}
