/* eslint-disable dot-notation */
import React, { useRef, useState } from "react";
import classNames from "classnames";
import { StyledProps, Omit } from "../_type";
import { ControlledProps, useDefaultValue } from "../form/controlled";
import { forwardRefWithStatics } from "../_util/forward-ref-with-statics";
import { useConfig } from "../_util/config-context";
import { SizeType } from "../_type/Size";
import { noop } from "../_util/noop";
import { KeyMap } from "../_util/key-map";
import { TextArea } from "./TextArea";
import { InputPassword } from "./InputPassword";

/**
 * Input 组件支持的属性。
 *
 * 除表格中列出的属性外，支持透传原生 `<input>` 标签支持的属性。
 */
export interface InputProps
  extends ControlledProps<string>,
    StyledProps,
    Omit<
      React.InputHTMLAttributes<HTMLInputElement>,
      "onChange" | "size" | "value" | "defaultValue"
    > {
  /**
   * 占位符
   */
  placeholder?: string;

  /**
   * 是否禁用
   * @default false
   */
  disabled?: boolean;

  /**
   * 是否为只读模式
   * @default false
   */
  readonly?: boolean;

  /**
   * 最大输入长度
   */
  maxLength?: number;

  /**
   * 原生 `<input>` 标签 `type` 属性
   */
  type?: React.InputHTMLAttributes<HTMLInputElement>["type"];

  /**
   * 输入框尺寸，使用 `full` 撑满容器宽度
   */
  size?: SizeType;

  /**
   * 按下回车键的回调
   * @since 2.7.0
   */
  onPressEnter?: (value: string, event: React.KeyboardEvent) => void;

  /**
   * 改变 Input 的基本样式类名，不建议使用
   */
  baseClassName?: string;

  /**
   * 是否多行输入
   *
   * **\[Deprecated\]** 请使用 `<Input.TextArea />` 组件
   * @deprecated
   */
  multiline?: boolean;

  /**
   * 行数
   *
   * **\[Deprecated\]** 请使用 `<Input.TextArea />` 组件
   * @deprecated
   */
  rows?: number;

  /**
   * 是否展示字数
   *
   * **\[Deprecated\]** 请使用 `<Input.TextArea />` 组件
   * @deprecated
   */
  showCount?: boolean;

  /**
   * Input 组件不应该传入 children
   */
  children?: never;
}

export const Input = forwardRefWithStatics(
  (props: InputProps, ref: React.Ref<HTMLInputElement>) => {
    const { classPrefix } = useConfig();
    const {
      children, // never
      multiline,
      placeholder,
      disabled,
      readonly,
      size,
      type,
      baseClassName,
      className,
      style,
      value,
      onChange,
      showCount,
      onCompositionStart = noop,
      onCompositionEnd = noop,
      onKeyPress = noop,
      onPressEnter = noop,
      ...restProps
    } = useDefaultValue(props, "");

    const composingRef = useRef(false);
    // 记录 `composition` 事件过程中值以实现受控
    const [composingRefValue, setComposingValue] = useState<string>("");

    const basename =
      baseClassName || `${classPrefix}-${multiline ? "textarea" : "input"}`;
    const inputClassName = classNames({
      [basename]: true,
      [className]: className,
      [`size-${size === "full" ? `${size}-width` : size}`]: size,
    });

    const hasRows = multiline && restProps.rows;

    const inputProps: React.InputHTMLAttributes<HTMLInputElement> = {
      placeholder,
      className: inputClassName,
      readOnly: readonly,
      disabled,
      // 受样式限制 rows 属性没有生效
      style: hasRows ? { height: "auto", ...(style || {}) } : style,
      value: composingRef.current ? composingRefValue : value,
      onChange: (event: React.ChangeEvent<HTMLInputElement>) => {
        if (composingRef.current) {
          setComposingValue(event.target.value);
        } else {
          onChange(event.target.value, { event });
        }
      },
      onCompositionStart: (event: React.CompositionEvent<HTMLInputElement>) => {
        composingRef.current = true;
        onCompositionStart(event);
      },
      onCompositionEnd: (event: React.CompositionEvent<HTMLInputElement>) => {
        if (composingRef.current) {
          composingRef.current = false;
          onChange(event.currentTarget.value, { event });
        }
        setComposingValue("");
        onCompositionEnd(event);
      },
      onKeyPress: (event: React.KeyboardEvent<HTMLInputElement>) => {
        if (event.key === KeyMap.Enter) {
          onPressEnter(event.currentTarget.value, event);
        }
        onKeyPress(event);
      },
      ...restProps,
    };

    if (multiline) {
      const component = <textarea ref={ref as any} {...(inputProps as any)} />;
      if (showCount) {
        const max = inputProps.maxLength;
        const len = value ? String(value).length : 0;
        return (
          <div className={`${classPrefix}-textarea-group`}>
            {component}
            <label className={`${classPrefix}-textarea__label`}>
              {max ? `${len} / ${max}` : len}
            </label>
          </div>
        );
      }
      return component;
    }

    return <input ref={ref} type={type} {...inputProps} />;
  },
  {
    /**
     * TextArea 组件
     */
    TextArea,

    /**
     * Password 组件
     */
    Password: InputPassword,

    /**
     * 在表单布局中，和 label 的默认对齐方式
     */
    defaultLabelAlign: "middle",
  }
);

Input.displayName = "Input";
