import { AppMenuFavoriteButton } from "./AppMenuFavoriteButton.js";
import type { AppMenuLink, AppMenuLinkGroup } from "./types.js";
import { useRovingTabIndex } from "./useRovingTabIndex.js";

export type AppMenuListProps = {
	groups: AppMenuLinkGroup[];
	/** Total number of links across all groups; the roving tab index size. */
	itemCount: number;
	/** Called when an entry that doesn't opt out with `keepOpen` is activated. */
	onClose: () => void;
	/** Without a handler no favorite toggles are rendered. */
	onToggleFavorite?: (id: string, favorite: boolean) => void;
};

/**
 * The app menu's right hand pane: the selected category's links, laid out as
 * titled groups of wrapping columns.
 *
 * The whole list is a single tab stop; the arrow keys move focus between the
 * links, following the visual grid.
 */
export function AppMenuList({ groups, itemCount, onClose, onToggleFavorite }: AppMenuListProps) {
	let roving = useRovingTabIndex(itemCount, { columns: true });

	// Links are numbered across all groups, since they share one roving index.
	let itemIndex = -1;

	function renderItem(item: AppMenuLink, index: number) {
		let props = {
			className: "ob-app-menu__link",
			...item.attributes,
			...roving.getItemProps(index),
		};

		function activate() {
			item.onClick?.();
			if (!item.keepOpen) onClose();
		}

		let link = item.href ? (
			<a {...props} href={item.href} target={item.target} rel={item.rel} onClick={activate}>
				{item.label}
			</a>
		) : (
			<button {...props} type="button" onClick={activate}>
				{item.label}
			</button>
		);

		// Only app entries carry an id and a favorite state; the fixed category
		// links (e.g. the developer tools) can't be favorited.
		if (!onToggleFavorite || item.id === undefined || typeof item.isFavorite !== "boolean") return link;

		let id = item.id;
		let isFavorite = item.isFavorite;

		return (
			<>
				{link}
				<AppMenuFavoriteButton
					appLabel={item.label}
					isFavorite={isFavorite}
					onToggle={() => onToggleFavorite(id, !isFavorite)}
					{...roving.getSecondaryProps(index)}
				/>
			</>
		);
	}

	return (
		<div className="ob-app-menu__columns" onKeyDown={roving.onKeyDown}>
			{groups.map((group, groupIdx) => (
				<section key={group.title ?? groupIdx} className="ob-app-menu__group">
					{group.title && <h2 className="ob-app-menu__group-title">{group.title}</h2>}
					<ul className="ob-app-menu__list">
						{group.items.map((item) => {
							itemIndex += 1;
							return (
								<li key={item.href ?? item.label} className="ob-app-menu__item">
									{renderItem(item, itemIndex)}
								</li>
							);
						})}
					</ul>
				</section>
			))}
		</div>
	);
}
