"use client";

/**
 * Multi Select Field
 * Renders a multi-select combobox with search and badge chips with X to remove
 */

import {
	Command,
	CommandEmpty,
	CommandGroup,
	CommandInput,
	CommandItem,
	CommandList,
} from "@mdxui/primitives/command";
import {
	Popover,
	PopoverContent,
	PopoverTrigger,
} from "@mdxui/primitives/popover";
import { ChevronsUpDown, X } from "lucide-react";
import { useState } from "react";
import {
	ANIMATION_CLASSES,
	getStaggerStyle,
	STAGGER_PRESETS,
} from "../animations";
import { cx, focusInput } from "../lib/utils";
import { OnboardingCheckbox } from "../primitives/onboarding-checkbox";
import { OnboardingLabel } from "../primitives/onboarding-label";
import type { MultiSelectFieldProps } from "../types/fields";

export function MultiSelectField({
	id,
	label,
	placeholder = "Select items...",
	searchPlaceholder = "Search...",
	emptyMessage = "No items found.",
	description,
	required = false,
	options,
	value,
	onChange,
	minSelections,
	maxSelections,
	animationIndex = 0,
	disabled = false,
	error,
	touched = false,
}: MultiSelectFieldProps) {
	const [open, setOpen] = useState(false);

	const handleSelect = (optionValue: string) => {
		if (value.includes(optionValue)) {
			onChange(value.filter((v) => v !== optionValue));
		} else {
			if (maxSelections && value.length >= maxSelections) {
				return;
			}
			onChange([...value, optionValue]);
		}
	};

	const handleRemove = (optionValue: string, e: React.MouseEvent) => {
		e.stopPropagation();
		onChange(value.filter((v) => v !== optionValue));
	};

	return (
		<div
			className={ANIMATION_CLASSES.fadeInUp}
			style={getStaggerStyle(
				animationIndex,
				STAGGER_PRESETS.formFields.baseDelay,
				STAGGER_PRESETS.formFields.increment,
				STAGGER_PRESETS.formFields.duration,
			)}
		>
			<OnboardingLabel
				className="mb-2 block text-base font-medium text-foreground"
				htmlFor={id}
			>
				{label}
				{required && <span className="ml-1 text-destructive">*</span>}
			</OnboardingLabel>

			{description && (
				<p className="mb-2 text-sm text-muted-foreground">{description}</p>
			)}

			<Popover open={open} onOpenChange={setOpen}>
				<PopoverTrigger asChild>
					<button
						type="button"
						id={id}
						role="combobox"
						aria-expanded={open}
						disabled={disabled}
						className={cx(
							"flex w-full select-none items-center justify-between gap-2 rounded-md border px-3 py-2 shadow-sm outline-none transition text-base sm:text-sm",
							"border-border",
							"text-foreground",
							"bg-background",
							"hover:bg-muted",
							"disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed",
							focusInput,
							value.length > 0 ? "h-auto min-h-[38px]" : "h-[38px]",
							touched && error && "border-destructive",
						)}
					>
						{value.length > 0 ? (
							<div className="flex flex-wrap gap-1 py-0.5">
								{value.map((v) => {
									const option = options.find((opt) => opt.value === v);
									return (
										<span
											key={v}
											className={cx(
												"inline-flex items-center gap-1 rounded-md px-2 py-0.5 text-xs font-medium",
												"bg-muted text-foreground",
												"border border-border",
											)}
										>
											{option?.label ?? v}
											<span
												role="button"
												tabIndex={0}
												className={cx(
													"rounded-sm outline-none transition-colors",
													"text-muted-foreground hover:text-foreground",
													"focus-visible:outline-2 focus-visible:outline-primary",
												)}
												onClick={(e) => handleRemove(v, e)}
												onKeyDown={(e) => {
													if (e.key === "Enter" || e.key === " ") {
														handleRemove(v, e as unknown as React.MouseEvent);
													}
												}}
											>
												<X className="size-3" />
												<span className="sr-only">
													Remove {option?.label ?? v}
												</span>
											</span>
										</span>
									);
								})}
							</div>
						) : (
							<span className="text-muted-foreground">{placeholder}</span>
						)}
						<ChevronsUpDown className="size-4 shrink-0 text-muted-foreground" />
					</button>
				</PopoverTrigger>
				<PopoverContent
					className={cx(
						"p-0 overflow-hidden",
						"min-w-(--radix-popover-trigger-width)",
						"w-(--radix-popover-trigger-width)",
					)}
					align="start"
					sideOffset={8}
				>
					<Command>
						<CommandInput placeholder={searchPlaceholder} />
						<CommandList className="max-h-[200px]">
							<CommandEmpty>{emptyMessage}</CommandEmpty>
							<CommandGroup>
								{options.map((option) => {
									const isSelected = value.includes(option.value);
									const isDisabled =
										option.disabled ||
										(!isSelected &&
											!!maxSelections &&
											value.length >= maxSelections);

									return (
										<CommandItem
											key={option.value}
											value={option.value}
											disabled={isDisabled}
											onSelect={() => handleSelect(option.value)}
											className="cursor-pointer"
										>
											<OnboardingCheckbox
												checked={isSelected}
												className="pointer-events-none"
											/>
											{option.label}
										</CommandItem>
									);
								})}
							</CommandGroup>
						</CommandList>
					</Command>
				</PopoverContent>
			</Popover>

			{minSelections && value.length < minSelections && (
				<p className="mt-1 text-xs text-muted-foreground">
					Select at least {minSelections} option{minSelections > 1 ? "s" : ""}
				</p>
			)}

			{maxSelections && (
				<p className="mt-1 text-xs text-muted-foreground">
					{value.length}/{maxSelections} selected
				</p>
			)}

			{touched && error && (
				<p className="mt-1.5 text-sm text-destructive">{error}</p>
			)}
		</div>
	);
}
