import { forwardRef } from 'react';
import type { SelectHTMLAttributes } from 'react';
import { cx } from '../../utils/cx';
import { useFallbackId } from '../../utils/useId';
import { Field } from '../Field/Field';
import type { FieldOwnProps } from '../Field/Field';
import './Select.css';

export interface SelectOption {
  label: string;
  value: string;
  disabled?: boolean;
}

export interface SelectProps
  extends Omit<SelectHTMLAttributes<HTMLSelectElement>, 'size' | 'children'>,
    FieldOwnProps {
  size?: 'sm' | 'md' | 'lg';
  /** The choices. Rendered as native `<option>` elements. */
  options: SelectOption[];
  /** Shown as a disabled first option when the value is empty. */
  placeholder?: string;
}

/**
 * Native single-select. Built on `<select>` so keyboard, mobile pickers and
 * form submission behave exactly as the platform intends.
 */
export const Select = forwardRef<HTMLSelectElement, SelectProps>(function Select(
  {
    size = 'md',
    options,
    placeholder,
    label,
    hint,
    error,
    required,
    fullWidth,
    id,
    className,
    style,
    defaultValue,
    value,
    ...rest
  },
  ref,
) {
  const selectId = useFallbackId(id);
  const messageId = `${selectId}-message`;
  const invalid = error != null;

  return (
    <Field
      label={label}
      hint={hint}
      error={error}
      required={required}
      fullWidth={fullWidth}
      htmlFor={selectId}
      messageId={messageId}
      className={className}
      style={style}
    >
      <div className="ds-select">
        <select
          {...rest}
          ref={ref}
          id={selectId}
          required={required}
          value={value}
          defaultValue={value === undefined && placeholder ? (defaultValue ?? '') : defaultValue}
          aria-invalid={invalid || undefined}
          aria-describedby={hint != null || invalid ? messageId : undefined}
          className={cx(
            'ds-control',
            `ds-control--${size}`,
            'ds-select__control',
            invalid && 'ds-control--invalid',
          )}
        >
          {placeholder && (
            <option value="" disabled>
              {placeholder}
            </option>
          )}
          {options.map((option) => (
            <option key={option.value} value={option.value} disabled={option.disabled}>
              {option.label}
            </option>
          ))}
        </select>
        <span className="ds-select__chevron" aria-hidden="true">
          <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5">
            <path d="M4 6l4 4 4-4" strokeLinecap="round" strokeLinejoin="round" />
          </svg>
        </span>
      </div>
    </Field>
  );
});
