import React from "react";
import Tooltip from "@beisen-phoenix/tooltip";
import { SelectProps, SelectValue } from "./PropsInterface";
import SwitchArrow from "./SwitchArrow";
import DeleteInputTxt from "./DelnputTxtIcon";
import Tags from "./Tags";
import { Item } from "./PropsInterface";
import utils from "@beisen-phoenix/common-utils";
const classes = utils.BEMClass("select");
import "./index.scss";

export interface SelectState extends SelectValue {
  inputValue: string;
  isFocus: boolean;
  isHasTooltip: boolean;
  visibleTxt: boolean;
  hover: boolean;
  searchWord: string;
  inputWidth: number;
  adjustArrow?: boolean;
}
const IE = /(msie\s|trident.*rv:)([\w.]+)/.test(
  navigator.userAgent.toLowerCase()
);

export default class Select extends React.PureComponent<
  SelectProps,
  SelectState
> {
  static defaultProps = {
    size: "normal",
    disabled: false,
    isMultiSelect: false,
    placeHolder: "",
    isSearch: false,
    readOnly: false,
    showDelete: true,
    translation: {}
  };

  private inputRef: React.RefObject<HTMLInputElement> = React.createRef();
  private hiddenSpanRef: React.RefObject<HTMLSpanElement> = React.createRef();
  private ulRef: React.RefObject<HTMLUListElement> = React.createRef();
  private clickDelet: boolean = false;

  constructor(props: SelectProps) {
    super(props);

    const { value } = this.props;
    this.state = {
      value,
      inputValue: "",
      isFocus: false,
      isHasTooltip: false,
      visibleTxt: true,
      hover: false,
      searchWord: "",
      inputWidth: 10,
      adjustArrow: false
    };
  }

  emitPropsChangeMethod = () => {
    const { onChange } = this.props;
    const { value, searchWord } = this.state;

    onChange &&
      onChange({
        value,
        searchWord
      });
  };

  handleValue = () => {
    const { isMultiSelect } = this.props;
    const { value } = this.state;

    return Array.isArray(value) && isMultiSelect ? value : "";
  };

  isShowToolTip = () => {
    const { hiddenSpanRef, inputRef } = this;
    const active = this.props.hasOwnProperty("isActive")
      ? this.props.isActive
      : this.state.isFocus;
    if (hiddenSpanRef.current && inputRef.current && !active) {
      const { current: spanCurrent } = hiddenSpanRef;
      const { current: inputCurrent } = inputRef;
      if (inputCurrent.clientWidth < spanCurrent.clientWidth) {
        this.setState({
          isHasTooltip: true
        });
        return;
      }
    }
    this.state.isHasTooltip &&
      this.setState({
        isHasTooltip: false
      });
  };

  adjustArrow = () => {
    if (IE && this.props.isMultiSelect) {
      const { current } = this.ulRef;
      const clientHeight = current!.clientHeight;
      const scrollHeight = current!.scrollHeight;
      if (scrollHeight > clientHeight) {
        !this.state.adjustArrow && this.setState({ adjustArrow: true });
      } else {
        this.state.adjustArrow && this.setState({ adjustArrow: false });
      }
      return;
    }
    this.state.adjustArrow && this.setState({ adjustArrow: false });
  };

  componentDidMount() {
    this.isShowToolTip();
    this.adjustArrow();
  }

  componentWillReceiveProps(nextProps: SelectProps) {
    "value" in nextProps &&
      this.props.value !== nextProps.value &&
      this.setState({ value: nextProps.value });
  }

  componentDidUpdate(prevProps: SelectProps) {
    this.isShowToolTip();
    this.adjustArrow();
    if (
      this.props.isSearch &&
      this.props.hasOwnProperty("isActive") &&
      !this.props.disabled
    ) {
      if (
        (this.props.hasOwnProperty("exitSearch") && this.props.exitSearch) ||
        !this.props.isActive
      ) {
        this.resetStatus();
      }
    }
  }

  resetStatus = () => {
    this.setState({
      isFocus: false,
      visibleTxt: true,
      inputValue: "",
      searchWord: "",
      value: this.props.value
    });
  };

  inputing = (evt: any) => {
    const searchWord = evt.target.value;
    const { isSearch, onSearch, readOnly } = this.props;

    if (!isSearch || readOnly) return;

    this.setState(
      {
        searchWord,
        inputValue: searchWord
        // value: this.handleValue()
      },
      () => {
        this.inputRef.current!.style.width = `${this.handleInputWidth()}px`;
      }
    );

    onSearch && onSearch(searchWord);
  };

  onBlur = (e: any) => {
    const isActive = !this.props.disabled && this.props.isActive;
    this.setState(
      {
        isFocus: isActive ? true : false,
        visibleTxt: isActive ? false : true,
        inputValue: "",
        searchWord: "",
        value: this.clickDelet ? "" : this.props.value
      },
      () => {
        this.clickDelet = false;
        if (this.props.isMultiSelect) {
          this.inputRef &&
            this.inputRef.current &&
            (this.inputRef.current.style.width = `10px`);
        }
      }
    );
  };

  onKeyDown = (e: any) => {
    const { keyCode, target } = e;

    if (keyCode === 8 && !target.value) {
      this.removeItem(-1);
    }
  };

  onWrapperClick = (e?: any) => {
    const { disabled, isSearch, isMultiSelect } = this.props;

    if (disabled) return;
    this.props.onClick && this.props.onClick(e);

    this.setState({
      visibleTxt: false
    });

    if (this.inputRef && this.inputRef.current && isSearch) {
      const value = isMultiSelect ? this.state.value : "";
      this.setState({
        isFocus: true,
        value
      });
      this.inputRef.current.focus();
    }
  };

  onWrapperMouseEnter = () => {
    this.setState({
      hover: true
    });
  };

  onWrapperMouseLeave = () => {
    this.setState({
      hover: false
    });
  };

  deleteTxt = e => {
    const {
      onDelete,
      isMultiSelect,
      isSearch,
      onSearch,
      isActive
    } = this.props;
    if (!isMultiSelect && isSearch && this.state.isFocus) {
      this.onWrapperClick(e);
      this.setState({ inputValue: "", searchWord: "" }, () => {
        onSearch && onSearch("");
      });

      return;
    }
    this.clickDelet = true;
    this.setState(
      {
        inputValue: "",
        value: this.handleValue()
      },
      this.emitPropsChangeMethod
    );

    onDelete && onDelete("");
  };

  removeItem = (item: Item | number): void => {
    const { value } = this.state;
    const { onDelete } = this.props;

    if (Array.isArray(value)) {
      const copied = [...value];

      if (typeof item === "number" && !isNaN(item)) {
        const temp = copied[item] || copied[copied.length - 1];

        !temp.disabled && copied.splice(item, 1);
      } else if (
        typeof item === "object" &&
        copied.includes(item) &&
        !item.disabled
      ) {
        copied.splice(copied.indexOf(item), 1);
      }

      if (copied.length !== value.length) {
        this.setState({ value: copied }, this.emitPropsChangeMethod);

        onDelete && onDelete(copied);
      }
    }
  };

  renderMutiItems = () => {
    const { isMultiSelect, disabled, size } = this.props;
    const { value } = this.state;

    if (Array.isArray(value) && isMultiSelect) {
      return value.map((item: Item, index) => (
        <Tags
          selectDisabled={disabled}
          key={`${item.value}${index}`}
          item={item}
          onClick={this.removeItem}
          size={size}
        />
      ));
    }
  };

  renderTxt = () => {
    const { size, disabled, isSearch, isActive } = this.props;
    const {
      isFocus,
      value,
      isHasTooltip,
      inputValue,
      visibleTxt,
      hover
    } = this.state;

    if (typeof value === "string" && value.length) {
      if (inputValue) return null;
      const editable = !disabled;
      const active =
        editable &&
        (this.props.hasOwnProperty("isActive") ? isActive : isFocus);
      const txtVisible = this.props.hasOwnProperty("isActive")
        ? !isActive
        : visibleTxt;
      const tipWrapperCls = classes({
        element: "tipWrapper",
        modifiers: {
          visible: txtVisible,
          large: size === "large",
          isSearch,
          disabled,
          active
        }
      });
      const tipCls = classes({ element: "tipEle", modifiers: { isSearch } });

      const TempComponent = (
        <span className={tipWrapperCls}>
          <span className={tipCls}>{value}</span>
        </span>
      );

      return value && isHasTooltip ? (
        <Tooltip title={value} visible={hover && !active}>
          {TempComponent}
        </Tooltip>
      ) : (
        TempComponent
      );
    }
  };

  handleInputWidth = () => {
    if (this.props.isMultiSelect) {
      const { hiddenSpanRef } = this;

      if (hiddenSpanRef.current) {
        const { current } = hiddenSpanRef;

        return current.clientWidth || 10;
      }
      return 10;
    }
  };

  switchDropDown = () => {
    // this.emitPropsChangeMethod();
  };

  isShowPlaceHolder = () => {
    const { inputValue, value } = this.state;
    if (inputValue) return;

    if (value && typeof value === "string") return;

    if (Array.isArray(value) && value.length) return;

    return true;
  };

  getInputValue = () => {
    const { inputValue, value } = this.state;

    if (inputValue) return inputValue;

    if (value && typeof value === "string" && !this.props.disabled) {
      return value;
    }

    return "";
  };

  getDeleteIconState() {
    const { inputValue, value } = this.state;
    const { disabled, readOnly, showDelete, isMultiSelect } = this.props;
    if (!showDelete || isMultiSelect) return false;
    if (disabled || readOnly) return false;
    if (inputValue) return true;
    if (value && typeof value === "string") return true;
  }

  render() {
    const {
      placeHolder,
      size,
      disabled,
      isMultiSelect,
      isSearch,
      error,
      isActive,
      translation = {},
      inputRef,
      extraCls,
      suffix
    } = this.props;
    const { inputValue, value, isFocus } = this.state;
    const multiValueLength =
      isMultiSelect && Array.isArray(value) ? value.length : void 0;
    const isShowDeleteIcon = this.getDeleteIconState();
    const editable = !disabled;
    const borderColorable = !disabled && !error;
    const active =
      editable && (this.props.hasOwnProperty("isActive") ? isActive : isFocus);
    const hideInput =
      (disabled && isMultiSelect) ||
      (!isSearch && multiValueLength && isMultiSelect);
    const singleSearch = !isMultiSelect && isSearch;

    const wrapperCls = classes({
      element: "",
      modifiers: {
        editable,
        borderColorable,
        singleSearch,
        multi: isMultiSelect,
        error,
        active,
        disabled,
        small: size === "small",
        large: size === "large",
        normal: size === "normal",
        exsitMultiValue: multiValueLength
      },
      extra: extraCls
    });
    const calcEleCls = classes({ element: "calcEle" });
    const placeHolderCls = classes({
      element: "placeHolder",
      modifiers: {
        active,
        large: size === "large",
        show: this.isShowPlaceHolder()
      }
    });
    const inputWrapperCls = classes({
      element: "inputWrapper",
      modifiers: { emptyMultiValue: !multiValueLength, isSearch }
    });
    const inputCls = classes({
      element: "input",
      modifiers: {
        disabled,
        large: size === "large",
        unText: !isSearch,
        multiInput: multiValueLength
      }
    });
    return (
      <div
        className={wrapperCls}
        onMouseEnter={this.onWrapperMouseEnter}
        onMouseLeave={this.onWrapperMouseLeave}
        onClick={this.onWrapperClick}
      >
        <span className={calcEleCls} ref={this.hiddenSpanRef}>
          {inputValue || (typeof value === "string" ? value : " ")}
        </span>
        <div className={placeHolderCls}>
          {this.props.value && !isMultiSelect
            ? this.props.value
            : placeHolder || translation.placeHolder}
        </div>
        <ul ref={this.ulRef} className={classes({ element: "content" })}>
          {this.renderMutiItems()}
          {!hideInput && (
            <li className={inputWrapperCls}>
              <input
                disabled={this.props.disabled}
                ref={ele => {
                  inputRef && inputRef(ele as HTMLInputElement);
                  this.inputRef = { current: ele };
                }}
                className={inputCls}
                value={this.getInputValue()}
                onChange={this.inputing}
                onKeyDown={this.onKeyDown}
              />
            </li>
          )}
          {this.renderTxt()}
        </ul>
        <SwitchArrow
          disabled={disabled}
          hide={isShowDeleteIcon}
          onClick={this.switchDropDown}
          adjustArrow={this.state.adjustArrow}
          suffix={suffix}
        />
        <DeleteInputTxt
          onClick={this.deleteTxt}
          isShowDeleteIcon={isShowDeleteIcon}
        />
      </div>
    );
  }
}
