import React from 'react';
import { FormBuilder, Connect, Popover, Input, Icon } from 'amos-framework';
import { fastDeepEqual, deepCopy } from 'amos-tool';
import { getPropsValue } from 'amos-designer';


const BasicForm = FormBuilder.BasicForm;
const enhanceForm = Connect.enhanceForm;
/**
 * 联想输入
 * @class TextInputViewpo
 * @extends {BasicForm}
 */
@enhanceForm
class TextInputViewpo extends BasicForm {

  constructor(props) {
    super(props);
    this.keybordIndex = -1;
    this.state = {
      loaded: false,
      open: false,
      data: []
    };
  }

  componentDidMount() {
    let _data = getPropsValue(this.props, 'data', {});
    if (_data.actionInit && _data.action) {
      _data.action().then(d => {
        const data = (d || []).map(e => ({ ...e, id: e[_data.keyName || 'id'], name: e[_data.labelName || 'name'] }));
        _data.items = deepCopy(data);
        this.setState({
          data
        });
      });
    }
    const value = getPropsValue(this.props, 'value', {});
    // 是否触发onChange事件
    if (value.triggerChange) {
      this.handleChange(value.id ? `TextInputViewpo_${value.id}` : value.name);
    }
  }

  componentDidUpdate(prevProps, prevState) {
    if (this.props.value && this.props.value.triggerChange) {
      if (!fastDeepEqual(this.props.value, prevProps.value)) {
        this.handleChange(this.props.value.id ? `TextInputViewpo_${this.props.value.id}` : this.props.value.name);
      }
    }
    let items = getPropsValue(this.props, 'data.items');
    if (!items) {
      items = this.state.data;
    }
  }

  onToggle = (open) => {
    let { width } = this.state;
    if (open) {
      width = this.node.input.clientWidth;
    }
    this.setState({ open, width });
  }

  handleChange = (value) => {
    let _data = getPropsValue(this.props, 'data.items');
    let actionInit = getPropsValue(this.props, 'data.actionInit', false);
    _data = _data ? _data : this.state.data;
    this.props.data.items = _data;
    if (value && value.includes('TextInputViewpo_')) {
      const _d = _data.find(e => e && `TextInputViewpo_${e.id}` === value) || {};
      this.props.onChange({ name: _d.name, id: _d.id });
    } else {
      this.props.onChange({ name: value, id: (_data.find(e => e && e.name === value) || {}).id });
    }
    if (getPropsValue(this.props, 'data.items', []).length === 0 && !actionInit) {
      this.requestData(value);
    }
  }

  requestData = (value) => {
    if (this.timeout) {
      clearTimeout(this.timeout);
      this.timeout = null;
    }
    this.currentValue = value;
    const fake = () => {
      const action = this.props.data.action;
      action(value).then(d => {
        if (this.currentValue === value) {
          this.setState({ data: d || [] });
        }
      });
    };
    const long = 300;
    this.timeout = setTimeout(fake, long);
  }

  handleSelect = (d) => () => {
    this.onToggle(false);
    this.handleChange(`TextInputViewpo_${d.id}`);
  }

  onBlur = () => {
    if (!this.blur) {
      this.blur = false;
      this.onToggle(false);
    }
  }
  /**
   * 输入框清除
   */
  handleClear = () => {
    this.handleChange('');
  }
  /**
   * 键盘控制下来框选择
   * @param {*} ev
   */
  handleKeyboard = (ev) => {
    if (this.options && this.options.children.length > 0) {
      if (ev.nativeEvent.keyCode === 38) {
        // ↑
        if (this.keybordIndex > 0) {
          this.options.children[this.keybordIndex] && this.options.children[this.keybordIndex].classList.remove('amos-select-option-active');
          this.keybordIndex = this.keybordIndex - 1;
          const optionDom = this.options.children[this.keybordIndex];
          optionDom.classList.add('amos-select-option-active');
          this.options.scrollTop = optionDom.offsetTop - this.options.offsetHeight + optionDom.clientHeight;
        }
      } else if (ev.nativeEvent.keyCode === 40) {
        // ↓
        if (this.keybordIndex < this.options.children.length - 1) {
          this.options.children[this.keybordIndex] && this.options.children[this.keybordIndex].classList.remove('amos-select-option-active');
          this.keybordIndex = this.keybordIndex + 1;
          const optionDom = this.options.children[this.keybordIndex];
          optionDom.classList.add('amos-select-option-active');
          this.options.scrollTop = optionDom.offsetTop - this.options.offsetHeight + optionDom.clientHeight;
        }
      } else if (ev.nativeEvent.keyCode === 13) {
        // enter
        this.options.children[this.keybordIndex] && this.options.children[this.keybordIndex].click();
        this.keybordIndex = -1;
      } else {
        this.options.children[this.keybordIndex] && this.options.children[this.keybordIndex].classList.remove('amos-select-option-active');
        this.keybordIndex = -1;
      }
    } else {
      this.keybordIndex = -1;
    }
  }

  render() {
    const value = getPropsValue(this.props, 'value', {});
    let _data = getPropsValue(this.props, 'data.items');
    _data = _data ? _data : this.state.data;
    const data = _data.filter(e => e && (e.name || '').toLocaleLowerCase().includes((value.name || '').toLocaleLowerCase()));
    return (
      <div className="gm-common-inputselect-wrapper">
        <Input
          ref={node => this.node = node}
          className="gm-common-inputselect"
          onFocus={() => this.onToggle(true)}
          onBlur={this.onBlur}
          onChange={(e) => this.handleChange(e.target.value)}
          value={value.name}
          onKeyUp={e => this.handleKeyboard(e)}
        />
        <div className="gm-common-inputselect-icons">
          {value.name && <Icon icon="cancel" onClick={this.handleClear} />}
        </div>
        <Popover
          className="gm-common-inputselect-popover-wrapper"
          contentWrapClassName="gm-common-inputselect-popover amos-select-dropdown-popover"
          open={this.state.open}
          onToggle={this.onToggle}
          content={
            <ul
              style={{ width: this.state.width }}
              onMouseOut={() => { this.blur = false; this.node.input.focus(); }}
              onMouseOver={() => this.blur = true}
              ref={node => this.options = node}
              className="amos-select-options"
            >
              {
                data.map(d => <li className="amos-select-option" key={`TextInputViewpo_${d.id}`} onClick={this.handleSelect(d)}>{d.name}</li>)
              }
            </ul>
          }
          direction="down"
          align="left"
          triggerMode="click"
          destroyContent
        >
          <div className="gm-common-inputselect-bar" />
        </Popover>
      </div>
    );
  }
}

TextInputViewpo.propTypes = {};

export default TextInputViewpo;
