import clsx from 'clsx';
import type { ForwardedRef, SelectHTMLAttributes } from 'react';
import { forwardRef } from 'react';
import { useId } from 'react';

type Attributes = Pick<
  SelectHTMLAttributes<HTMLSelectElement>,
  'disabled' | 'name' | 'onBlur' | 'onFocus' | 'required'
>;

export type SelectItem<T> = Readonly<{
  label: string;
  value: T;
}>;

export type SelectDisplay = 'block' | 'inline';

type Props<T> = Readonly<{
  display?: SelectDisplay;
  isLabelHidden?: boolean;
  label: string;
  name?: string;
  onChange: (value: string) => void;
  options: ReadonlyArray<SelectItem<T>>;
  value: T;
}> &
  Readonly<Attributes>;

function Select<T>(
  {
    display,
    disabled,
    label,
    isLabelHidden,
    options,
    value,
    onChange,
    ...props
  }: Props<T>,
  ref: ForwardedRef<HTMLSelectElement>,
) {
  const id = useId();

  return (
    <div>
      <label
        className={clsx(
          'mb-1 block text-sm font-medium text-slate-700',
          isLabelHidden && 'sr-only',
        )}
        htmlFor={id ?? undefined}>
        {label}
      </label>
      <select
        ref={ref}
        aria-label={isLabelHidden ? label : undefined}
        className={clsx(
          display === 'block' && 'block w-full',
          'focus:border-primary-500 focus:ring-primary-500 rounded-md border-slate-300 py-2 pl-3 pr-10 text-base focus:outline-none sm:text-sm',
          disabled && 'bg-slate-100',
        )}
        disabled={disabled}
        id={id}
        value={String(value)}
        onChange={(event) => {
          onChange(event.target.value);
        }}
        {...props}>
        {options.map(({ label: optionLabel, value: optionValue }) => (
          <option key={String(optionValue)} value={String(optionValue)}>
            {optionLabel}
          </option>
        ))}
      </select>
    </div>
  );
}

export default forwardRef(Select);