"use client";

import * as React from "react";

import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { cn } from "@/lib/utils";

/** Radix Select requires non-empty option values; used when `allowEmpty` maps "" ↔ empty choice. */
export const REACT_SELECT_EMPTY_VALUE = "__empty__";

export type ReactSelectOption = {
  value: string;
  label: React.ReactNode;
  disabled?: boolean;
};

const defaultLabelClassName =
  "text-[10px] font-semibold uppercase tracking-wide text-[#575a62]";

export type ReactSelectProps = {
  value?: string;
  onValueChange?: (value: string) => void;
  options: ReactSelectOption[];
  placeholder?: string;
  disabled?: boolean;
  /** When true, prepends an empty option and maps its selection to `""`. */
  allowEmpty?: boolean;
  /** Label for the empty option when `allowEmpty` (default "—"). */
  emptyOptionLabel?: string;
  /** Accessible name for the trigger when no visible label is provided. */
  "aria-label"?: string;
  id?: string;
  label?: React.ReactNode;
  required?: boolean;
  labelClassName?: string;
  wrapperClassName?: string;
  triggerClassName?: string;
  contentClassName?: string;
  size?: "sm" | "default";
  position?: React.ComponentProps<typeof SelectContent>["position"];
  align?: React.ComponentProps<typeof SelectContent>["align"];
};

const defaultTriggerClassBySize: Record<NonNullable<ReactSelectProps["size"]>, string> = {
  default: "w-full min-w-0 bg-white/60 border-white",
  sm:
    "w-full min-w-0 bg-white/60 border-white text-[11px] px-2 min-[1500px]:px-[10px] min-[1500px]:text-[12px] min-[1500px]:[&_svg]:size-4 [&_svg]:size-3",
};

export function ReactSelect({
  value,
  onValueChange,
  options,
  placeholder = "Select…",
  disabled = false,
  allowEmpty = false,
  emptyOptionLabel = "—",
  "aria-label": ariaLabel,
  id,
  label,
  required,
  labelClassName,
  wrapperClassName,
  triggerClassName,
  contentClassName,
  size = "default",
  position,
  align,
}: ReactSelectProps) {
  const resolvedOptions = React.useMemo(() => {
    if (!allowEmpty) return options;
    return [
      { value: REACT_SELECT_EMPTY_VALUE, label: emptyOptionLabel },
      ...options,
    ];
  }, [allowEmpty, emptyOptionLabel, options]);

  const selectValue =
    allowEmpty && (value === "" || value == null)
      ? REACT_SELECT_EMPTY_VALUE
      : value;

  const handleValueChange = (next: string) => {
    if (allowEmpty && next === REACT_SELECT_EMPTY_VALUE) {
      onValueChange?.("");
      return;
    }
    onValueChange?.(next);
  };

  const select = (
    <Select
      value={selectValue}
      onValueChange={handleValueChange}
      disabled={disabled}
    >
      <SelectTrigger
        id={id}
        size={size}
        className={cn(defaultTriggerClassBySize[size], triggerClassName)}
        aria-label={ariaLabel}
      >
        <SelectValue placeholder={placeholder} />
      </SelectTrigger>
      <SelectContent
        position={position}
        align={align}
        className={contentClassName}
      >
        {resolvedOptions.map((option) => (
          <SelectItem
            key={option.value}
            value={option.value}
            disabled={option.disabled}
          >
            {option.label}
          </SelectItem>
        ))}
      </SelectContent>
    </Select>
  );

  const wrappedSelect = wrapperClassName ? (
    <div className={wrapperClassName}>{select}</div>
  ) : (
    select
  );

  if (label == null) {
    return wrappedSelect;
  }

  return (
    <div className={cn("flex flex-col gap-1", wrapperClassName)}>
      <label
        htmlFor={id}
        className={cn(defaultLabelClassName, labelClassName)}
      >
        {label}
        {required ? (
          <span className="ml-0.5 text-destructive" aria-hidden>
            *
          </span>
        ) : null}
      </label>
      {select}
    </div>
  );
}
