import cx from "classnames";
import React from "react";

const CLASS_ROOT = "text-input";

export type TextInputSize = "default" | "large";
export type TextInputWidth = "3ch" | "8ch" | "12ch" | "default" | "fullwidth";
export type TextInputType =
  | "email"
  | "hidden"
  | "password"
  | "search"
  | "tel"
  | "number"
  | "text"
  | "url";

export type TextInputSearchIcon = "none" | "transient" | "persistent";

export interface TextInputProps
  extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "size"> {
  /** Input html type. */
  htmlType?: TextInputType;
  /** Html id attribute. */
  id: string;
  /** Disabled state. */
  isDisabled?: boolean;
  /** Invalid state */
  isInvalid?: boolean;
  /** Readonly state. */
  isReadonly?: boolean;
  /** Valid state */
  isValid?: boolean;
  /** Html name attribute. If not present, id is used.*/
  name?: string;
  /** Placeholder text */
  placeholder?: string;
  /** Size of element. */
  size?: TextInputSize;
  /** Input value. */
  value?: string;
  /** Input width */
  width?: TextInputWidth;
  /** Additional CSS classes */
  className?: string;
  /** Search icon mode. `transient` shows icon only on empty unfocused input, `persistent` keeps it visible with placeholder. */
  searchIcon?: TextInputSearchIcon;
}

const defaultProps = {
  htmlType: "text" as TextInputType,
  size: "default" as TextInputSize,
  width: "default" as TextInputWidth,
  searchIcon: "none" as TextInputSearchIcon,
};

const TextInput = React.forwardRef<HTMLInputElement, TextInputProps>(
  (
    {
      className,
      id,
      isDisabled,
      isInvalid,
      isValid,
      isReadonly,
      placeholder,
      size = defaultProps.size,
      htmlType = defaultProps.htmlType,
      width = defaultProps.width,
      searchIcon = defaultProps.searchIcon,
      name,
      ...other
    },
    ref,
  ) => {
    const hasSearchIcon = searchIcon === "transient";
    const hasSearchIconWithPlaceholder = searchIcon === "persistent";

    const classes = cx(
      CLASS_ROOT,
      {
        "is-invalid": isInvalid,
        "is-valid": isValid,
        [`${CLASS_ROOT}--${size}`]: size !== defaultProps.size,
        [`${CLASS_ROOT}--${width}`]: width !== defaultProps.width,
      },
      className,
    );

    const inputName = name || id;

    const inputElement = (
      <input
        className={classes}
        id={id}
        name={inputName}
        type={htmlType}
        disabled={isDisabled}
        readOnly={isReadonly}
        placeholder={placeholder}
        ref={ref}
        {...other}
      />
    );

    if (hasSearchIcon || hasSearchIconWithPlaceholder) {
      return (
        <span
          className={cx("text-input__wrapper", {
            "text-input__wrapper--search-icon": hasSearchIcon,
            "text-input__wrapper--search-icon-with-placeholder":
              hasSearchIconWithPlaceholder,
          })}
        >
          {inputElement}
        </span>
      );
    }

    return inputElement;
  },
);

TextInput.displayName = "TextInput";

export { TextInput };
