import * as stylex from "@stylexjs/stylex";
import {
	type ButtonHTMLAttributes,
	type DetailedHTMLProps,
	type PropsWithChildren,
	type ReactElement,
	memo,
} from "react";

import { color, controlWeight, font, fontSize, size } from "./tokens.stylex";

import ToggleSliderInput from "./ToggleSliderInput";

const CAN_HOVER = "@media (hover: hover)";

const styles = stylex.create({
	list: {
		width: "100%",
		padding: "0",
		margin: "0",
		display: "flex",
		flexDirection: "column",
	},

	noBorder: {
		borderStyle: "none",
	},

	item: {
		backgroundColor: color.gray500,
		borderBottomWidth: {
			default: "0px",
			":not(:last-child)": "1px",
		},
		borderBottomStyle: {
			default: "none",
			":not(:last-child)": "solid",
		},
		borderBottomColor: {
			default: "transparent",
			":not(:last-child)": color.gray400,
		},
	},

	text: {
		padding: size.px4,
	},

	heading: {
		backgroundColor: color.transparent,
	},

	critical: {
		color: color.red150,
	},

	stack: {
		display: "flex",
		flexDirection: "column",
		gap: size.px4,
		width: "100%",
	},

	labelContent: {
		flex: "1",
	},

	buttonColumns: {
		display: "flex",
		gap: size.px4,
		width: "100%",
	},

	buttonBase: {
		fontFamily: font.main,
		fontSize: fontSize.body,
		fontWeight: controlWeight.button,
		// TODO: color

		padding: size.px4,

		display: "flex",
		alignItems: "center",
		gap: size.px4,

		cursor: "pointer",

		backgroundColor: {
			default: color.gray500,
			":active": color.gray400,
			[CAN_HOVER]: {
				":hover": color.gray400,
			},
		},
	},

	icon: {
		display: "flex",
		fontSize: "120%", // TODO: ASK-UX proportional icon size?
	},

	columnButton: {
		flexDirection: "column",
		flex: "1",

		cursor: "pointer",

		backgroundColor: {
			default: color.gray500,
			":active": color.gray400,
			[CAN_HOVER]: {
				":hover": color.gray400,
			},
		},
	},

	largeIcon: {
		display: "flex",
		fontSize: "150%", // TODO: ASK-UX proportional icon size?
	},

	disabled: {},
});

export type DrawerListProps = PropsWithChildren;

/**
 * @remarks The drawer components are meant to be used in a <BottomDrawer /> for mobile only.
 * 			Do not use them in other contexts. Especially not on desktop.
 */
export const DrawerList = memo(function DrawerList({
	children,
}: DrawerListProps) {
	return <div {...stylex.props(styles.list)}>{children}</div>;
});

export type DrawerListItemProps = PropsWithChildren;

/**
 * @remarks The drawer components are meant to be used in a <BottomDrawer /> for mobile only.
 * 			Do not use them in other contexts. Especially not on desktop.
 */
export const DrawerListItem = memo(function DrawerListItem({
	children,
}: DrawerListItemProps) {
	return (
		<div {...stylex.props(styles.noBorder, styles.item)}>{children}</div>
	);
});

export interface DrawerListTextItemProps extends PropsWithChildren {
	heading?: boolean;
}

/**
 * @remarks The drawer components are meant to be used in a <BottomDrawer /> for mobile only.
 * 			Do not use them in other contexts. Especially not on desktop.
 */
export const DrawerListTextItem = memo(function DrawerListTextItem({
	heading,
	children,
}: DrawerListTextItemProps) {
	return (
		<div
			{...stylex.props(
				styles.noBorder,
				styles.item,
				styles.text,
				heading && styles.heading,
			)}
		>
			{children}
		</div>
	);
});

type NativeButtonProps = DetailedHTMLProps<
	ButtonHTMLAttributes<HTMLButtonElement>,
	HTMLButtonElement
>;

/**
 * @remarks The drawer components are meant to be used in a <BottomDrawer /> for mobile only.
 * 			Do not use them in other contexts. Especially not on desktop.
 */
export interface DrawerListButtonItemProps extends PropsWithChildren {
	type?: NativeButtonProps["type"];
	role?: NativeButtonProps["role"];
	icon?: ReactElement<unknown>;
	onClick?: () => void;
	critical?: boolean;
	// TODO:
	// disabled
	// title
}

/**
 * @remarks The drawer components are meant to be used in a <BottomDrawer /> for mobile only.
 * 			Do not use them in other contexts. Especially not on desktop.
 */
export const DrawerListButtonItem = memo(function DrawerListTextItem({
	type,
	role,
	icon,
	onClick,
	critical,
	children,
}: DrawerListButtonItemProps) {
	return (
		<button
			type={type ?? "button"}
			role={role}
			{...stylex.props(
				styles.noBorder,
				styles.item,
				styles.buttonBase,
				critical && styles.critical,
			)}
			onClick={onClick}
		>
			{icon && <span {...stylex.props(styles.icon)}>{icon}</span>}
			{children}
		</button>
	);
});

export type DrawerStackProps = PropsWithChildren;

/**
 * @remarks The drawer components are meant to be used in a <BottomDrawer /> for mobile only.
 * 			Do not use them in other contexts. Especially not on desktop.
 */
export const DrawerStack = memo(function DrawerStack({
	children,
}: DrawerStackProps) {
	return <div {...stylex.props(styles.stack)}>{children}</div>;
});

export type DrawerButtonColumnProps = PropsWithChildren;

/**
 * @remarks The drawer components are meant to be used in a <BottomDrawer /> for mobile only.
 * 			Do not use them in other contexts. Especially not on desktop.
 */
export const DrawerButtonColumn = memo(function DrawerButtonColumn({
	children,
}: DrawerButtonColumnProps) {
	return <div {...stylex.props(styles.buttonColumns)}>{children}</div>;
});

export interface DrawerButtonProps {
	icon?: ReactElement<unknown>;
	type?: NativeButtonProps["type"];
	role?: NativeButtonProps["role"];
	onClick?: () => void;
	critical?: boolean;
	text: string;
}

/**
 * @remarks The drawer components are meant to be used in a <BottomDrawer /> for mobile only.
 * 			Do not use them in other contexts. Especially not on desktop.
 */
export const DrawerButton = memo(function DrawerButton({
	icon,
	type,
	role,
	onClick,
	critical,
	text,
}: DrawerButtonProps) {
	return (
		<button
			type={type ?? "button"}
			role={role}
			onClick={onClick}
			{...stylex.props(
				styles.noBorder,
				styles.buttonBase,
				styles.columnButton,
				critical && styles.critical,
			)}
		>
			{icon && <span {...stylex.props(styles.largeIcon)}>{icon}</span>}
			{text}
		</button>
	);
});

type NativeInputProps = DetailedHTMLProps<
	ButtonHTMLAttributes<HTMLInputElement>,
	HTMLInputElement
>;

export interface DrawerListToggleSwitchItemProps {
	label: string;
	name?: NativeInputProps["name"];
	icon?: ReactElement<unknown>;
	disabled?: NativeInputProps["disabled"];
	defaultChecked?: boolean;

	/** `value` and `onChange` are optional because we want to be able to use the control in an uncontrolled manner as well (for example, in forms) */
	value?: boolean;
	onChange?: (value: boolean) => void;
}

/**
 * @remarks The drawer components are meant to be used in a <BottomDrawer /> for mobile only.
 * 			Do not use them in other contexts. Especially not on desktop.
 */
export const DrawerListToggleSwitchItem = memo(function DrawerListToggleItem({
	label,
	name,
	icon,
	disabled,
	defaultChecked,
	value,
	onChange,
}: DrawerListToggleSwitchItemProps) {
	return (
		// biome-ignore lint/a11y/noLabelWithoutControl: <input> is inside ToggleSliderInput
		<label
			{...stylex.props(
				styles.noBorder,
				styles.item,
				styles.buttonBase,
				disabled && styles.disabled,
			)}
		>
			{icon && <span {...stylex.props(styles.icon)}>{icon}</span>}
			<span {...stylex.props(styles.labelContent)}>{label}</span>
			<ToggleSliderInput
				defaultChecked={defaultChecked}
				disabled={disabled}
				name={name}
				onChange={onChange}
				value={value}
				title={label}
			/>
		</label>
	);
});
