import {useEffect, useMemo, useState, useRef} from 'react';
import {Tooltip, Spin, AutoComplete, Tree, Modal} from 'antd';
import {PlusOutlined, ReloadOutlined} from '@ant-design/icons';
import { useContextMenu, Menu as RcMenu, Item as RcItem } from "react-contexify";

import { dispatch } from '../../../../../model';
import {highlightSearchContentByTerms, showMessage} from '../../../../../util';
import UpdateDefineTreeNodeModal from './UpdateDefineTreeNodeModal';

import 'react-contexify/dist/ReactContexify.css';
import './DefineTree.less';

const {Option} = AutoComplete;

const DefineTree = (props) => {
  const {onClick} = props;
  const [loading, setLoading] = useState(false);
  const [data, setData] = useState();
  const [options, setOptions] = useState([]);
  const [keyword, setKeyword] = useState('');
  const [expandedKeys, setExpandedKeys] = useState([]);
  const [selectedKeys, setSelectedKeys] = useState([]);
  const [autoExpandParent, setAutoExpandParent] = useState(false);
  const [updateNodeModalVisible, setUpdateNodeModalVisible] = useState(false);
  const [updateNodeType, setUpdateNodeType] = useState('');
  const [rightSelectNode, setRightSelectNode] = useState({});

  const selectedKeysRef = useRef([]);
  const [modal, contextHolder] = Modal.useModal();
  const MENU_ID = 'msd-define-tree';
  const { show } = useContextMenu({
    id: MENU_ID,
  });

  useEffect(() => {
    getTreeNodes();
    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  const treeData = useMemo(() => {
    const loop = (data) =>
      (data||[]).map((item) => {
        if (item.children) {
          return {
            title: item.name||'',
            key: item._id||'',
            origin: item,
            children: loop(item.children),
          };
        }

        return {
          title: item.name||'',
          key: item._id||'',
        };
      });

    return loop(data);
  }, [data])

  const treeList = useMemo(() => {
    const generateList = (data, list, path = null) => {
      (data||[]).forEach(node => {
        const {_id, name} = node;

        const currentPath = path ? `${path}/${name}` : name;
        list.push({key: _id, title: currentPath});
        if (node.children) {
          generateList(node.children, list, currentPath);
        }
      });
    };

    const newTreeList = [];
    generateList(data, newTreeList);
    
    return newTreeList;
    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [data])

  const selectNode = useMemo(() => {
    const generateList = (data, list) => {
      (data||[]).forEach(node => {
        list.push({...node});
        if (node.children) {
          generateList(node.children, list);
        }
      });
    };

    const newTreeList = [];
    generateList(data, newTreeList);
    
    const filterNodes = newTreeList.filter(item => selectedKeys.indexOf(item._id)!==-1);
    
    return (filterNodes||[]).length>0 ? filterNodes[0]:{};
    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [data, selectedKeys])

  const getTreeNodes = () => {
    setLoading(true);
    dispatch({
      type: 'msd.getTreeNodes',
      callback: (data) => {
        setLoading(false);
        setData(data||[]);

        if ((selectedKeysRef.current||[]).length===0 && (data||[]).length>0) {
          onTreeSelect([data[0]._id]);
        }

        if ((expandedKeys||[]).length===0 && (data||[]).length>0) {
          setExpandedKeys([data[0]._id]);
        } else {
          setExpandedKeys(Array.from(new Set([...expandedKeys, ...selectedKeysRef.current])));
          setAutoExpandParent(true);
        }
      },
      error: () => {
        setLoading(false);
      }
    })
  }

  const onAddClick = () => {
    setUpdateNodeType('add');
    setUpdateNodeModalVisible(true);
  }

  const onRefreshClick = () => {
    getTreeNodes();
  }

  const updateNode = () => {
    setUpdateNodeType('update');
    setUpdateNodeModalVisible(true);
  }

  const upOrDownNode = (steps = 1) => {
    setLoading(true);
    dispatch({
      type: 'msd.treeNodeSeq',
      payload: {
        params: {
          id: rightSelectNode?._id||'',
          steps
        }
      },
      callback: () => {
        rightSelectNode?._id && onTreeSelect([rightSelectNode?._id]);
        getTreeNodes();
      },
      error: () => {
        setLoading(false);
      }
    })
  }

  const deleteNode = () => {
    modal.confirm({
      title: '提示!',
      content: '删除目录会删除相关的模版,您确定删除吗?',
      onOk: () => {
        setLoading(true);
        dispatch({
          type: 'msd.deleteTreeNode',
          payload: {
            params: {
              nodeId: rightSelectNode?._id
            }
          },
          callback: () => {
            showMessage('success', '删除目录成功');
            setLoading(false);
            if (selectedKeysRef.current.indexOf(rightSelectNode?._id)!==-1) {
              setSelectedKeys([]);
              selectedKeysRef.current = [];
            }

            getTreeNodes();
          }, 
          error: () => {
            setLoading(false);
          }
        });
      }
    });
  }

  const onAutoCompleteSearch = (searchText) => {
    setKeyword(searchText);
    setOptions(treeList.filter(item => item.title.indexOf(searchText)!==-1));
  };

  const onAutoCompleteSelect = (value, option) => {
    const paths = value.split('/');
    setKeyword(paths[paths.length-1]);

    onTreeSelect([option.key]);
    setExpandedKeys(Array.from(new Set([...expandedKeys, option.key])));
    setAutoExpandParent(true);
  };

  const onAutoCompleteClear = () => {
    setKeyword('');
  }

  const onTreeExpand = (expandedKeys) => {
    setExpandedKeys(expandedKeys);
    setAutoExpandParent(false);
  }

  const onTreeSelect = (selectedKeys) => {
    if (selectedKeys.length === 0) {
      return;
    }

    setSelectedKeys(selectedKeys);
    selectedKeysRef.current = selectedKeys;
    onClick && onClick(selectedKeys[0]);
  }

  const onUpdateNodeModalCancel = (refresh = false, nodeId = null) => {
    setUpdateNodeModalVisible(false);

    if (refresh) {
      nodeId && onTreeSelect([nodeId]);

      getTreeNodes();
    }
  }

  return (
    <div className='data-master-tree'>
      <div className='header p-3'>
        <Tooltip title="新增目录">
          <PlusOutlined 
            className='default' 
            onClick={onAddClick} 
            style={{ 
              fontSize:16,
              cursor:'pointer',
              flex: 1  
            }} 
          />
        </Tooltip>
        <Tooltip title="刷新目录" className='ml-2'>
          <ReloadOutlined 
            className='default' 
            onClick={onRefreshClick} 
            style={{ 
              fontSize:16,
              cursor:'pointer',
              flex: 1  
            }} 
          />
        </Tooltip>
        <div style={{flex: 3}} />
      </div>
      <div className='content p-3'>
        <Spin spinning={loading}>
          <AutoComplete
            className='content-search'
            allowClear
            value={keyword}
            onSelect={onAutoCompleteSelect}
            onSearch={onAutoCompleteSearch}
            onClear={onAutoCompleteClear}
          >
          {
            (options||[]).map((item, index) => {
              return (
                <Option key={item.key} value={item.title}>
                  <div style={{ whiteSpace: 'normal' }}>
                  {highlightSearchContentByTerms(item.title, [keyword])}
                  </div>
                </Option>
              );
            })
          }
          </AutoComplete>
          <Tree
            className='content-tree'
            showLine 
            showIcon={false} 
            autoExpandParent={autoExpandParent}
            treeData={treeData}
            onExpand={onTreeExpand}
            onSelect={onTreeSelect}
            expandedKeys={expandedKeys}
            selectedKeys={selectedKeys}
            onRightClick={({event, node}) => {
              setRightSelectNode(node?.origin);
              show(event, {
                position: {
                  x: event.clientX + 30,
                  y: event.clientY - 10
                }
              });
            }}
          />
        </Spin>
      </div>
      
      <UpdateDefineTreeNodeModal 
        visible={updateNodeModalVisible}
        onCancel={onUpdateNodeModalCancel}
        type={updateNodeType}
        node={(updateNodeType==='add')?selectNode:rightSelectNode}
      />

      <RcMenu id={MENU_ID}>
        <RcItem id="edit" onClick={updateNode}>
          修改目录
        </RcItem>
        <RcItem id="up" onClick={() => { upOrDownNode(-1); }}>
          上移目录
        </RcItem>
        <RcItem id="down" onClick={() => { upOrDownNode(1); }}>
          下移目录
        </RcItem>
        <RcItem id="delete" onClick={deleteNode}>
          删除目录
        </RcItem>
      </RcMenu> 
      {contextHolder}  
    </div>
  );
}

export default DefineTree;