import React, { Component } from 'react';
import { NestedMenu, Popover, Tree, Input,Checkbox } from 'amos-framework';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { deepCopy } from 'amos-tool';
import { tools } from '@gm/graphmod-utils';
import ImageConsts from '@gm/graphmod-assets';
import Tip from './../tip';
import Btn from './../btns/Btn';
import RenameInput from './RenameInput';
import './FireTree.scss';

const imgs = ImageConsts.common;
const TreeNode = Tree.TreeNode;
const MenuItem = NestedMenu.Item;
const SubMenu = NestedMenu.SubMenu;
const newadd = 'newadd';
const rename = 'rename';
const deletedata = 'delete';
/**
 *  tree组件
 *
 *
 * @class TreeBox
 * @extends {Component}
 */
class TreeBox extends Component {
  static propTypes = {
    className: PropTypes.string, // 样式名称
    treeData: PropTypes.array, // 数据数据
    renderIcon: PropTypes.func, // 渲染节点第一个图标函数
    renderChildIcon: PropTypes.func, // 渲染节点第二个图标函数
    renderTypeIcon: PropTypes.func, // 渲染树节点类型图标函数
    onSearchChange: PropTypes.func, // 搜索值改变事件
    onkeydownFun: PropTypes.func, // 搜索值改变事件
    renderMeuns: PropTypes.func, // 渲染节点菜单
    renderName: PropTypes.func, // 渲染节点显示名称
    searchValue: PropTypes.string, // 搜索值
    onSearch: PropTypes.func, // 点击搜索按钮函数
    treeName: PropTypes.string, // 节点显示名称属性
    header: PropTypes.any, // 顶部搜索区替换搜索内容
    expandedKeys: PropTypes.array, // 展开节点的唯一值数组
    onExpandedRowsChange: PropTypes.func, // 初始展开函数
    alwaysExpandedKeys: PropTypes.array, // 一直展开的节点key
    onDelete: PropTypes.func, // 删除
    deleteTip: PropTypes.string, // 删除提示
    onRename: PropTypes.func, // 重命名
    onNew: PropTypes.func, // 新建
    onSelect: PropTypes.func,
    selectedKeys: PropTypes.array, // 选择的节点
    treeKey: PropTypes.string, // 作为树节点字段
    checkName: PropTypes.string,
    onCheckChange: PropTypes.func
  };

  static defaultProps = {
    treeData: [],
    treeName: 'name',
    treeKey: 'id',
    onExpandedRowsChange() {}
  };

  constructor(props) {
    super(props);
    this.state = {
      showInput: {},
      newFolderData: {},
      expandedKeys: [], // 树选中节点key
      open: {}
    };
  }

  onToggle = (openFlag, key) => {
    const { open } = this.state;
    open[key] = openFlag;
    this.setState({ open });
  };
  /**
   * 重命名
   * @param {*} key
   */
  rename = data => {
    const { treeKey } = this.props;
    const { showInput } = this.state;
    showInput[data[treeKey]] = true;
    this.setState({ showInput });
  };
  /**
   * 删除文件夹
   */
  deleteFolder = data => {
    const { deleteTip, treeData, treeKey } = this.props;
    Tip.confirm(deleteTip || '您确定要删除吗?').then(() => {
      this.props.onDelete(data, () => {
        Tip.success('删除成功');
        const parent =
          tools.recursive(treeData).findParent(e => {
            return e[treeKey] === data[treeKey];
          }) || {};
        this.props.onSelect(parent[treeKey], parent);
      });
    });
  };
  /**
   * 新建文件夹
   */
  newFolder = data => {
    const { treeKey } = this.props;
    const { expandedKeys } = this.props;
    this.newFolderFlag = true;
    const newExpandedKeys = [...new Set([...expandedKeys, data[treeKey]])];
    this.setState({ newFolderData: data, expandedKeys: newExpandedKeys });
    this.props.onExpandedRowsChange(newExpandedKeys);
  };
  /**
   * 重命名失去焦点
   * @param {*} data
   * @param {*} event
   */
  handleBlur = (data, event) => {
    const { treeKey, treeData, treeName } = this.props;
    const { showInput } = this.state;
    const newName = event.target.value;
    if (newName && newName.trim() && newName.trim() !== data[treeName]) {
      const parent =
        tools.recursive(treeData).findParent(e => {
          return e[treeKey] === data[treeKey];
        }) || {};
      const otherData = (parent.chilren || []).find(e => e[treeKey] !== data[treeKey] && e[treeName] === newName.trim());
      if (otherData) {
        Tip.error(`《${data[treeName]}》名称在此位置下已存在`);
      } else {
        this.props.onRename(data, newName.trim(), newData => {
          showInput[data[treeKey]] = false;
          this.setState({ showInput });
          if (newData) {
            this.props.onSelect(newData[treeKey], newData);
          }
        });
      }
    } else {
      showInput[data[treeKey]] = false;
      this.setState({ newFolderData: {} });
    }
  };

  handleNewBlur = (data, event) => {
    const { treeKey, treeData, treeName } = this.props;
    const newName = event.target.value;
    this.setState({ newFolderData: {} });
    if (newName && newName.trim()) {
      const parent =
        tools.recursive(treeData).find(e => {
          return e[treeKey] === data.parentId;
        }) || {};
      const otherData = (parent.chilren || []).find(e => e[treeKey] !== data[treeKey] && e[treeName] === newName.trim());
      if (otherData) {
        Tip.error(`《${data[treeName]}》名称在此位置下已存在`);
      } else {
        this.props.onNew(parent, newName, newData => {
          if (newData) {
            this.props.onSelect(newData[treeKey], newData);
          }
        });
      }
    }
  };
  /**
   * 点击菜单
   * @param {*} data
   * @param {*} event
   * @param {*} menus
   */
  handleClick = (data, event, menus) => {
    if (menus.key === rename) {
      this.rename(data);
    } else if (menus.key === newadd) {
      this.newFolder(data);
    } else if (menus.key === deletedata) {
      this.deleteFolder(data);
    }
  };
  /**
   * 树选择
   *
   * @param {*} keys
   * @param {*} data
   */
  handleSelect = (keys, selectedNode) => {
    const { treeKey } = this.props;
    this.props.onSelect(selectedNode.node.props.dataRef[treeKey], selectedNode.node.props.dataRef);
  };
  /**
   * 渲染单个菜单
   * @param {*} menus
   * @param {*} data
   */
  renderMenusItem = (menus, data) => {
    const { treeKey } = this.props;
    return (menus || [])
      .filter(e => !e.hide)
      .map(m => {
        const img = m.icon ? <img src={m.icon} alt="" /> : <div className="mod-com-firetree-menu-img" />;
        if (!m.children || m.children.length === 0) {
          return (
            <MenuItem
              key={m.key}
              onClick={event => {
                event.stopPropagation();
                this.onToggle(false, data[treeKey]);
                m.click && m.click(data, event);
                if (!m.click) {
                  this.handleClick(data, event, m);
                }
              }}
              className={classnames({ 'mod-com-firetree-menudivider': m.showDivider })}
              text={
                <div className="mod-com-firetree-menuitem-content">
                  {img}
                  {m.text}
                </div>
              }
            />
          );
        } else {
          return (
            <SubMenu
              text={
                <div className="mod-com-firetree-menuitem-content">
                  {img}
                  {m.text}
                </div>
              }
            >
              {this.renderMenusItem(m.children, data)}
            </SubMenu>
          );
        }
      });
  };
  /**
   * 渲染菜单
   * @param {*} data
   * @param {*} menus
   */
  renderMenu = (data, menus) => {
    return <NestedMenu className="mod-com-firetree-menu">{this.renderMenusItem(menus, data)}</NestedMenu>;
  };

  renderTitle = item => {
    const { treeKey, treeName, renderName } = this.props;
    const { showInput } = this.state;
    const img = this.props.renderIcon && this.props.renderIcon(item);
    const childIcon = this.props.renderChildIcon && this.props.renderChildIcon(item);
    const typeIcon = this.props.renderTypeIcon && this.props.renderTypeIcon(item);

    let menus = this.props.renderMeuns && this.props.renderMeuns(item);
    menus = menus && menus.filter(e => !e.hide);
    return (
      <span className="mod-com-firetree-item" title={item[treeName]}>
        {img && <img src={img} alt="" />}
        {typeIcon && <img className="child-icon" src={typeIcon} alt="" />}
        {childIcon && <img className="child-icon" src={childIcon} alt="" />}
        <span ref={node => this[item[treeKey]] = node}>
          {renderName && renderName(item)}
          {item.menuTreeNewFolder && !renderName && <RenameInput defaultValue={item[treeName]} onOk={event => this.handleNewBlur(item, event)} />}
          {!renderName ?
            !showInput[item[treeKey]] ? (
              <span>{item[treeName]}</span>
            ) : (
              <RenameInput defaultValue={item[treeName]} onOk={event => this.handleBlur(item, event)} />
            )
            : null}
        </span>
        {menus && menus.length > 0 && !item.menuTreeNewFolder && !showInput[item[treeKey]] && (
          <Popover
            content={this.renderMenu(item, menus)}
            contentWrapClassName="mod-com-firetree-popover"
            className="mod-com-firetree-popover-wrapper"
            direction="down"
            open={this.state.open[item[treeKey]]}
            onToggle={flag => this.onToggle(flag, item[treeKey])}
            align="left"
            triggerMode="click"
          >
            <div className="mod-com-firetree-tree-more">
              <svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fit="" height="1em" width="1em" preserveAspectRatio="xMidYMid meet" focusable="false">
                <g id="lbnormal/more" strokeWidth="1" fillRule="evenodd">
                  <g id="lb编组" transform="translate(2 7)">
                    <path d="M10 2.5V0h2.5v2.5H10zm-5 0V0h2.5v2.5H5zm-5 0V0h2.5v2.5H0z" id="lb形状结合" />
                  </g>
                </g>
              </svg>
            </div>
          </Popover>
        )}
      </span>
    );
  };

  /**
   * 数据渲染
   * @param {*} data
   */
  renderTreeNodes = data => {
    const { treeKey } = this.props;
    return (
      data &&
      data.map(item => {
        if (item.children) {
          return (
            <TreeNode title={this.renderTitle(item)} key={item[treeKey]} dataRef={item}>
              {this.renderTreeNodes(item.children)}
            </TreeNode>
          );
        }
        return <TreeNode dataRef={item} title={this.renderTitle(item)} key={item[treeKey]} />;
      })
    );
  };

  render() {
    const {
      className,
      treeData,
      selectedKeys,
      alwaysExpandedKeys,
      treeKey,
      treeName,
      onSearchChange,
      onkeydownFun,
      searchValue,
      onSearch,
      header,
      expandedKeys,
      onExpandedRowsChange,
      checkName,
      onCheckChange
    } = this.props;
    const { newFolderData } = this.state;
    let dataTree = treeData;
    if (newFolderData && newFolderData[treeKey]) {
      dataTree = tools.recursive(treeData).map(e => {
        if (e[treeKey] === newFolderData[treeKey]) {
          if (((e.children || [])[0] || {})[treeKey] !== 'new') {
            e.children = [{ [treeKey]: 'new', [treeName]: '', menuTreeNewFolder: true, parentId: e[treeKey] }, ...e.children || []];
          }
        }
        return e;
      });
    } else {
      if (this.newFolderFlag) {
        dataTree = tools.recursive(treeData).filter(e => e[treeKey] !== 'new');
        this.newFolderFlag = false;
      }
    }
    return (
      <div className={classnames('mod-com-firetree', className)}>
        <div className="mod-com-firetree-header">
          {header || (
            <React.Fragment>
              <Input placeholder="搜索" value={searchValue} onKeyDown={e => onkeydownFun(e)} onChange={e => onSearchChange(e.target.value)} />
              <Btn onClick={() => onSearch()} icon={imgs.search} />
            </React.Fragment>
          )}
        </div>
        {checkName && <Checkbox className="mod-com-firetree-check" onChange={e => onCheckChange(e.target.checked)} onClick={e=>{}} >{checkName}</Checkbox>}
        <div className="mod-com-firetree-content mod-com-scrollbar">
          <Tree
            expandedKeys={
              expandedKeys
                ? [...new Set([...expandedKeys.map(e => String(e)), ...(alwaysExpandedKeys || []).map(e => String(e))])]
                : [...new Set([...this.state.expandedKeys.map(e => String(e)), ...(alwaysExpandedKeys || []).map(e => String(e))])]
            }
            onSelect={this.handleSelect}
            selectedKeys={selectedKeys}
            showDashLine
            onExpand={d => this.setState({ expandedKeys: d }, () => onExpandedRowsChange(d))}
          >
            {this.renderTreeNodes(dataTree)}
          </Tree>
        </div>
      </div>
    );
  }
}
/**
 * 搜索树
 * @param {string} searchValue 搜索值
 * @param {array} list 树数据
 * @param {string} name 搜索值的属性名称
 * @param {array} noSearchData 不进行搜索过滤的数据项唯一值数组
 * @param {string} key 树的唯一值属性名
 * @param {array} expandedKeys 当前树展开的节点
 * @param {func} getExpand 是否需要搜索结果进行展开的唯一值集合
 * @param {bool} valueType 是否是唯一值搜索，true 是通过唯一值搜索 false 文本搜索
 */
TreeBox.getSearchData = (searchValue, list, name, noSearchData, key, expandedKeys, getExpand, valueType) => {
  list = deepCopy(list);
  if (!searchValue || !searchValue.trim()) {
    return { searchData: list, expandedKeys };
  }
  const searchData = tools.recursive(list).search(d => {
    if (noSearchData.some(e => e === d[key])) {
      return true;
    }
    if (!valueType) {
      if (d[name].toLocaleLowerCase().includes(searchValue.trim().toLocaleLowerCase())) {
        return true;
      }
    } else {
      // eslint-disable-next-line eqeqeq
      if (d[key] == searchValue) {
        return true;
      }
    }
  });
  const res = [];
  if (getExpand) {
    tools.recursive(searchData).map(e => {
      res.push(e[key]);
      return e;
    });
  }
  return { searchData, expandedKeys: res };
};

TreeBox.rename = rename;
TreeBox.new = newadd;
TreeBox.delete = deletedata;

export default TreeBox;
