import React from 'react';
import classNames from 'classnames';
import PropTypes from 'prop-types';
import Dialog from '../../dialog/src/DialogWrap';
import Button from '../../button/lib/Button';
import Icon from '../../icon';
// @require '../style/index.scss'

const TypeID = PropTypes.oneOfType([
  PropTypes.number,
  PropTypes.string,
]).isRequired;

/**
 * 判断 selectedIdList 和 preselectedIdList 列表里是否有对应id的元素
 * @param list
 * @param id
 * @return {boolean}
 */
function listHasId(list, id) {
  for (let i = 0; i < list.length; i++) {
    let one = list[i];
    if (one === id) {
      return true;
    }
  }
  return false;
}

/**
 * 选择组件
 */
class Picker extends React.Component {
  static propTypes = {
    /**
     * 是否可见
     */
    visible: PropTypes.bool,
    /**
     * 被选择的名词名称
     */
    name: PropTypes.string,
    /**
     * 解释说明
     */
    detail: PropTypes.string,
    /**
     * css z-index
     */
    zIndex: PropTypes.number,
    /**
     * @transformable
     * 数据
     * 如果data==null 会显示正在加载中 直到传入非null的data;
     * id: 用于跟踪选项 必须保证唯一性;
     * search: 用于搜索时的关键字匹配, 如果search==null，search=id;
     * display: 用于在列表里显示每个选项的样子, 如果该属性是react元素将把这个元素显示在选项列表里否则将作为文字显示, 如果display==null，display=id
     */
    data: PropTypes.arrayOf(PropTypes.shape({
      /**
       * 用于跟踪选项 必须保证唯一性
       */
      id: TypeID,
      /**
       * 用于搜索时的关键字匹配
       * 如果search==null，search=id
       */
      search: PropTypes.string,
      /**
       * 用于在列表里显示每个选项的样子
       * 如果该属性是react元素将把这个元素显示在选项列表里否则将作为文字显示
       * 如果display==null，display=id
       */
      display: PropTypes.any,
    })),
    /**
     * @transformable
     * 被选中的id列表
     * 被选中在右边,没有被选中在左边
     */
    selectedIdList: PropTypes.arrayOf(TypeID),
    /**
     * @transformable
     * 被预选中的id列表
     * 被预选中背景颜色是蓝色，当点击添加或切换后会切换selected
     */
    preselectedIdList: PropTypes.arrayOf(TypeID),
    /**
     * 当被选中或没有被选中的项发生变化时回调
     */
    onChange: PropTypes.func,
    /**
     * 保存修改，当被关闭时调用
     */
    onSave: PropTypes.func,
    /**
     * 放弃修改，当被关闭时调用
     */
    onClose: PropTypes.func,
    /**
     * 最多可以被选中几个，
     * 0表示没有限制
     */
    maxSelected: PropTypes.number,
    /**
     * 当正在搜索时回调
     * callback(searchKeyword,data)
     */
    onSearch: PropTypes.func,
    /**
     * 当左边当选择选项区滑动到底部时想要获得更多的可展示数据时调用
     * callback(searchKeyword,data)
     */
    onNeedMoreData: PropTypes.func,
    /**
     * 当前是否正在加载数据中
     * 是的话会在左边选项列表最下面显示加载中
     */
    loading: PropTypes.bool,
    /**
     * @transformable
     * 警告信息，会以红色的文字显示在中间
     * 当 warning==null || warning.length===0 时不会显示警告信息，否则会显示
     */
    warning: PropTypes.string,
    style: PropTypes.object,
    className: PropTypes.string,
  };

  static defaultProps = {
    visible: false,
    name: '',
    detail: '',
    zIndex: 1050,
    maxSelected: 0,
    loading: false,
  };

  state = {
    // 搜索关键字
    searchKeyword: '',
    // 警告信息
    warning: this.props.warning,
  };

  constructor(props) {
    super(props);
    this.handleProps(this.props);
  }

  handleProps = (props, setState) => {
    const { data, selectedIdList, preselectedIdList, warning } = props;
    if (Array.isArray(data)) {
      // 对data 的 option 依次检查
      data.forEach(option => {
        let id = option.id;
        if (Array.isArray(selectedIdList)) {
          option.selected = listHasId(selectedIdList, id);
        }
        if (Array.isArray(preselectedIdList)) {
          option.preselected = listHasId(preselectedIdList, id);
        }
        // 如果search==null，search=id
        if (option.search == null) {
          option.search = String(id);
        }
        // 如果display==null，display=id
        if (option.display == null) {
          option.display = id;
        }
      });
    }
    if (setState) {
      this.setState({
        warning,
      });
    }
  };

  componentWillReceiveProps(nextProps) {
    this.handleProps(nextProps, true);
  }

  componentDidMount() {
    this.notifyNeedMoreData();
  }

  notifyNeedMoreData = () => {
    const { onNeedMoreData, data } = this.props;
    const { searchKeyword } = this.state;
    if (typeof onNeedMoreData === 'function') {
      onNeedMoreData(searchKeyword, data);
    }
  };

  close = () => {
    const { onClose } = this.props;
    if (typeof onClose === 'function') {
      onClose();
    }
  };

  save = () => {
    const { onSave } = this.props;
    if (typeof onSave === 'function') {
      let selectedList = [];
      let data = this.props.data;
      if (data instanceof Array) {
        data.forEach(one => {
          if (one.selected) {
            selectedList.push(one);
          }
        });
        onSave(selectedList);
      }
    }
    this.close();
  };

  onUnselectedScroll = (event) => {
    const ul = event.currentTarget;
    if (ul.offsetHeight + ul.scrollTop >= ul.scrollHeight) {
      window.clearTimeout(this.timeout);
      this.timeout = window.setTimeout(() => {
        this.notifyNeedMoreData();
      }, 100);
    }
  };

  onSearchInputChange = (event) => {
    const { onSearch, data } = this.props;
    const searchKeyword = event.currentTarget.value;
    this.setState({
      searchKeyword,
    });
    if (typeof onSearch === 'function') {
      onSearch(searchKeyword, data);
    }
  };

  onOptionClick = (option) => {
    const { data, maxSelected } = this.props;
    option.preselected = !option.preselected;
    if (!option.selected && maxSelected !== 0) {
      let hasSelectedCount = 0;
      data.forEach(one => {
        if (one.selected) {
          hasSelectedCount++;
        } else if (one.preselected) {
          hasSelectedCount++;
        }
      });
      // 对于maxSelected===1的特色情况优化交互
      if (maxSelected === 1 && hasSelectedCount >= 2) {
        data.forEach(one => {
          one.selected = false;
          one.preselected = false;
        });
        option.preselected = true;
      } else if (hasSelectedCount > maxSelected) {
        option.preselected = false;
        this.setState({
          warning: `最多能选中${maxSelected}个`,
        });
        return;
      }
    }
    this.setState({
      warning: null,
    });
  };

  mockOption = (option) => {
    return (
      <li
        key={option.id}
        onClick={() => this.onOptionClick(option)}
        style={{ backgroundColor: option.preselected ? '#e5e5e5' : null }}
      >
        {option.display}
      </li>
    );
  };

  notifyChange = () => {
    const { onChange } = this.props;
    if (typeof onChange === 'function') {
      onChange(this.props.data);
    }
  };

  updatePreselectedWith = (value) => {
    const { data } = this.props;
    data.forEach(option => {
      if (option.preselected) {
        option.selected = value;
        option.preselected = false;
      }
    });
    this.forceUpdate();
    this.notifyChange();
  };

  render() {
    const { style, className, visible, name, detail, zIndex, data, loading } = this.props;
    const { searchKeyword, warning } = this.state;
    // 显示在右边的已经被选中的选项
    let selectedList = [];
    // 显示在左边的没有被选中的选项
    let unselectedList = [];
    let enableAdd = false;
    let enableRemove = false;
    if (Array.isArray(data)) {
      data.forEach(one => {
        if (one.selected) {
          selectedList.push(one);
          if (one.preselected) {
            enableRemove = true;
          }
        } else {
          if (one.search.indexOf(searchKeyword) >= 0) {
            unselectedList.push(one);
          }
          if (one.preselected) {
            enableAdd = true;
          }
        }
      });
    }
    return (
      <Dialog
        visible={visible}
        title={`选择${name}`}
        zIndex={zIndex}
        closeable
        size="medium"
        onClose={this.close}
        className="im-picker-dialog"
        button={[
          <Button size="s" key="yes" onClick={this.save}>确定</Button>,
          <Button size="s" color="weak" key="no" onClick={this.close}>取消</Button>]}
      >
        <div className={classNames('im-picker', className)} style={style}>
          <div className="im-picker-left">
            <h4>可选择的{name}</h4>
            <div className="im-picker-select">
              <input
                value={searchKeyword}
                placeholder="输入关键字筛选"
                onChange={this.onSearchInputChange}
              />
              <ul onScroll={this.onUnselectedScroll}>
                {unselectedList.map(one => this.mockOption(one))}
                {data == null || loading ?
                  <li className="im-picker-loading" onClick={() => this.notifyNeedMoreData()}>
                    <i className="im-picker-loading-icon"> </i></li> : null}
              </ul>
            </div>
          </div>
          <div className="im-picker-center">
            <Button
              size="s"
              color="weak"
              disabled={!enableAdd}
              onClick={() => this.updatePreselectedWith(true)}
            >添加<Icon
              type="v-right"
            /></Button>
            <Button
              size="s"
              color="weak"
              disabled={!enableRemove}
              style={{ marginLeft: 0 }}
              onClick={() => this.updatePreselectedWith(false)}
            ><Icon
              type="v-left"
            />删除</Button>
            <p className="im-picker-detail">{detail}</p>
            <p className="im-picker-warn">{warning}</p>
          </div>
          <div className="im-picker-right">
            <h4>已选择的{name}</h4>
            <div className="im-picker-select">
              <ul>{selectedList.map(one => this.mockOption(one))}</ul>
            </div>
          </div>
        </div>
      </Dialog>
    );
  }
}
export default Picker;
