import { forwardRef } from 'react';
import type { InputHTMLAttributes, ReactNode } from 'react';
import { cx } from '../../utils/cx';
import { useFallbackId } from '../../utils/useId';
import { Field } from '../Field/Field';
import type { FieldOwnProps } from '../Field/Field';
import './Input.css';

export type InputSize = 'sm' | 'md' | 'lg';

export interface InputProps
  extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size'>,
    FieldOwnProps {
  size?: InputSize;
  /** Non-interactive adornment inside the field, before the text. */
  iconStart?: ReactNode;
  /** Non-interactive adornment inside the field, after the text. */
  iconEnd?: ReactNode;
}

/** Single-line text field with an optional label, hint and error message. */
export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
  {
    size = 'md',
    label,
    hint,
    error,
    required,
    fullWidth,
    iconStart,
    iconEnd,
    id,
    className,
    style,
    type = 'text',
    ...rest
  },
  ref,
) {
  const inputId = useFallbackId(id);
  const messageId = `${inputId}-message`;
  const invalid = error != null;

  return (
    <Field
      label={label}
      hint={hint}
      error={error}
      required={required}
      fullWidth={fullWidth}
      htmlFor={inputId}
      messageId={messageId}
      className={className}
      style={style}
    >
      <div
        className={cx(
          'ds-input',
          iconStart && 'ds-input--has-start',
          iconEnd && 'ds-input--has-end',
        )}
      >
        {iconStart && (
          <span className="ds-input__icon ds-input__icon--start" aria-hidden="true">
            {iconStart}
          </span>
        )}
        <input
          {...rest}
          ref={ref}
          id={inputId}
          type={type}
          required={required}
          aria-invalid={invalid || undefined}
          aria-describedby={hint != null || invalid ? messageId : undefined}
          className={cx('ds-control', `ds-control--${size}`, invalid && 'ds-control--invalid')}
        />
        {iconEnd && (
          <span className="ds-input__icon ds-input__icon--end" aria-hidden="true">
            {iconEnd}
          </span>
        )}
      </div>
    </Field>
  );
});
