import { ReactNode, forwardRef } from 'react';

import { assertEmptyObject } from '../../utils/assertEmptyObject';
import { BaseTextField, BaseTextFieldProps } from '../BaseTextField/BaseTextField';
import { BaseTextFieldType } from '../BaseTextField/constants';

import { TextFieldType } from './constants';

export interface TextFieldProps extends Omit<BaseTextFieldProps<string>, 'type'> {
  /**
   * Element that will be appended to {@link TextField} as suffix.
   * Should be only {@link FieldSuffixIconButton} or {@link FieldSuffixTextButton}
   */
  suffix?: ReactNode;
  /**
   * Element that will be appended to {@link TextField} as prefix.
   * Should be only {@link FieldPrefixIcon}.
   */
  prefix?: ReactNode;
  /**
   * Type of the `input` element.
   *
   * @default {@link TextFieldType.Text}
   */
  type?: TextFieldType;
}

/**
 * Field that allow typing some text.
 *
 * ```tsx
 * import { TextField } from 'ui-kit';
 *
 * <TextField value="any text" onChange={console.log} />
 * ```
 *
 * ## Prefix
 *
 * {@link TextField} support only one prefix option:
 * - icon prefix by {@link FieldPrefixIcon}
 *
 * <Story id="form-textfield--with-icon-prefix" />
 *
 * ## Suffix
 *
 * {@link TextField} support two suffix variant:
 * - text button suffix by {@link FieldSuffixTextButton}
 * - icon button suffix by {@link FieldSuffixIconButton}
 *
 * ### Text button suffix
 *
 * To add button as suffix to {@link TextField} use {@link FieldSuffixTextButton} as
 * {@link TextFieldProps.suffix} prop.
 *
 * <Story id="form-textfield--with-suffix-text-button" />
 *
 * ### Icon button suffix
 *
 * To add button as suffix to {@link TextField} use {@link FieldSuffixIconButton} as
 * {@link TextFieldProps.suffix} prop.
 *
 * <Story id="form-textfield--with-suffix-icon-button" />
 */
export const TextField = forwardRef<HTMLInputElement, TextFieldProps>((props, ref) => {
  const {
    type = TextFieldType.Text,
    ariaInvalid,
    ariaLabel,
    ariaDescribedBy,
    ariaErrorMessage,
    disabled,
    onChange,
    prefix,
    suffix,
    className,
    id,
    onBlur,
    value,
    placeholder,
    required,
    ariaRequired,
    testId,
    ...rest
  } = props;
  assertEmptyObject(rest);

  return (
    <BaseTextField
      ref={ref}
      ariaDescribedBy={ariaDescribedBy}
      ariaErrorMessage={ariaErrorMessage}
      ariaInvalid={ariaInvalid}
      ariaLabel={ariaLabel}
      ariaRequired={ariaRequired}
      className={className}
      disabled={disabled}
      id={id}
      onBlur={onBlur}
      onChange={onChange}
      placeholder={placeholder}
      prefix={prefix}
      required={required}
      suffix={suffix}
      testId={testId}
      type={type as unknown as BaseTextFieldType}
      value={value}
    />
  );
});
