/**
 * The tab switcher (milestone 23, ruling 4).
 *
 * The hand-rolled version spelled the ARIA attributes by hand but had no
 * keyboard navigation; React Aria brings arrow-key movement and roving
 * tabindex with the same roles. State stays inside RAC — no caller needs to
 * read which tab is open.
 *
 * RAC exposes state as render-prop booleans, so every rule below is a
 * boolean-guarded style object: StyleX cannot express `[data-selected]`.
 */

import type { ReactNode } from "react";
import * as stylex from "@stylexjs/stylex";
import { Tab, TabList, TabPanel, Tabs as AriaTabs } from "react-aria-components";
import { colors } from "./tokens.stylex";

export interface TabSpec {
	id: string;
	label: string;
	content: ReactNode;
}

interface Props {
	/** The tab list's accessible name. */
	label: string;
	tabs: readonly TabSpec[];
	/**
	 * The open tab, when a caller owns the selection — the configuration pages
	 * keep it in the URL. Omit both of these to let RAC hold the state, which
	 * is what a tab set with no linkable identity wants.
	 */
	selectedKey?: string;
	onSelectionChange?: (key: string) => void;
}

const styles = stylex.create({
	list: {
		display: "flex",
		gap: "0.5rem",
		marginTop: "1rem",
		borderBottomWidth: 1,
		borderBottomStyle: "solid",
		borderBottomColor: colors.border,
	},
	tab: {
		marginBottom: -1,
		borderBottomWidth: 2,
		borderBottomStyle: "solid",
		borderBottomColor: "transparent",
		paddingInline: "0.75rem",
		paddingBlock: "0.5rem",
		fontWeight: 500,
		color: colors.textMuted,
		cursor: "pointer",
	},
	tabSelected: {
		borderBottomColor: colors.primary,
		color: colors.primaryOnSurface,
	},
	tabHovered: {
		color: colors.text,
	},
	/**
	 * The milestone-9 focus floor. A Tab is a `div` with a roving tabindex, so
	 * the ring is driven by RAC's `isFocusVisible` rather than `:focus-visible`.
	 */
	tabFocusVisible: {
		outlineWidth: 2,
		outlineStyle: "solid",
		outlineColor: colors.focus,
		outlineOffset: 2,
	},
	panel: {
		outlineStyle: "none",
	},
	/** Explicit, so RAC's default `react-aria-Tabs` class does not land instead. */
	root: {
		display: "block",
	},
});

export default function Tabs({ label, tabs, selectedKey, onSelectionChange }: Props) {
	return (
		<AriaTabs
			selectedKey={selectedKey}
			onSelectionChange={onSelectionChange === undefined ? undefined : (key) => onSelectionChange(String(key))}
			className={() => stylex.props(styles.root).className ?? ""}
		>
			<TabList aria-label={label} className={() => stylex.props(styles.list).className ?? ""}>
				{tabs.map((tab) => (
					<Tab
						key={tab.id}
						id={tab.id}
						className={({ isSelected, isHovered, isFocusVisible }) =>
							stylex.props(
								styles.tab,
								isHovered && !isSelected && styles.tabHovered,
								isSelected && styles.tabSelected,
								isFocusVisible && styles.tabFocusVisible,
							).className ?? ""
						}
					>
						{tab.label}
					</Tab>
				))}
			</TabList>
			{tabs.map((tab) => (
				<TabPanel key={tab.id} id={tab.id} className={() => stylex.props(styles.panel).className ?? ""}>
					{tab.content}
				</TabPanel>
			))}
		</AriaTabs>
	);
}
