import React, { useState, useEffect } from "react";
import { Tooltip, Tree, Modal, Spin, Dropdown, Menu, Button } from "antd";
import { PlusOutlined, SyncOutlined, ImportOutlined, UnorderedListOutlined, ReloadOutlined } from '@ant-design/icons';
import classnames from 'classnames';
import { useContextMenu, Menu as RcMenu, Item as RcItem } from "react-contexify";

import UpdateTreeItemModal from './UpdateTreeItemModal';
import { dispatch } from '../../../../model'; 
import { showMessage, getQueryParam } from '../../../../util';
import { AnchorId, AnchorDirId, AnchorTimestamp, AnchorRequireId } from '../../../../util/constant';

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

const viewModes = [
  {
    key: 'dir',
    name: '目录视角'
  },
  {
    key: 'state',
    name: '模型状态视角'
  },
  {
    key: 'requirement',
    name: '数据需求视角'
  }
];

const ModelTree = (props) => {

  const MENU_ID = 'model-tree';

  const { show } = useContextMenu({
    id: MENU_ID,
  });

  const { onSelect, onViewChange, refrence='', importStockModel, keyword } = props;
  const [ loading, setLoading ] = useState(false);
  const [ treeData, setTreeData ] = useState(null);
  const [ item, setItem ] = useState(null);
  const [ prevItem, setPrevItem ] = useState(null);
  const [ visible, setVisible ] = useState(false);
  const [ type, setType ] = useState(null);
  const [ rootId, setRootId ] = useState('');
  const [ expandedKeys, setExpandedKeys ] = useState([]);
  const [ autoExpandParent, setAutoExpandParent ] = useState(false);
  const [ viewSelectedKey, setViewSelectedKey ] = useState(viewModes[0].key);
  const [ isSetRootId, setIsSetRootId ] = useState(true);
  const [ domains, setDomains ] = useState([]);
  const [ domainSelectedKey, setDomainSelectedKey ] = useState('');
  const [ currentRightClickDir, setCurrentRightClickDir ] = useState({});

  const [modal, contextHolder] = Modal.useModal();

  const timestamp = getQueryParam(AnchorTimestamp, props.location?.search||'');
  const id = getQueryParam(AnchorId, props.location?.search||'');
  const did = getQueryParam(AnchorDirId, props.location?.search||'');
  const rid = getQueryParam(AnchorRequireId, props.location?.search||'');

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

  useEffect(() => {
    if (refrence === 'recatalog') {
      getDirTreeData();
    } else {
      setViewSelectedKey(viewModes[0].key);
      onViewChange && onViewChange(viewModes[0].key);

      if ((id||'') !== '') {
        getDataModelLocationThenGetDirTreeData();
      } else if ((did||'') !== '') {
        getDirTreeData(did);
      } else if (rid) {
        setViewSelectedKey('requirement');
        onViewChange && onViewChange('requirement');
        getRequirementTreeData(rid);
      } else {
        getDirTreeData();
      }  
    }

    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [timestamp])

  useEffect(() => {

    if (keyword!=='') {
      if (item && !prevItem) {
        setPrevItem(item);
      }

      setItem(null);
    } else {
      if (prevItem && !item) {
        setItem(prevItem);
        onSelect && onSelect(prevItem?.key||'');
        setPrevItem(null);
      }
    }

    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [ keyword ])

  const getShowSyncAndDomains = () => {
    dispatch({
      type: 'datamodel.isSetRootDomainId',
      callback: data => {
        if (data === 'false') {
          dispatch({
            type: 'user.getDomains',
            callback: _data => {
              setDomains(_data||[]);
              setIsSetRootId(false);
            }
          });
        } else {
          setIsSetRootId(true);
        }
      }
    });
  }

  const getDataModelLocationThenGetDirTreeData = () => {
    setLoading(true);
    dispatch({
      type: 'datamodel.getDataModelLocation',
      payload: {
        id
      },
      callback: data => {
        getDirTreeData(data.easyDataModelerDataModelCatalogId||'', data.offset);
      },
      error: () => {
        setLoading(false);
        getDirTreeData();
      }
    });
  }

  const getDirTreeData = (defaultSelectedId='', offset=null, type='refresh') => {

    setLoading(true);
    dispatch({
      type: (type==='refresh')?'datamodel.refreshDataModelCatalog':'datamodel.loadDataModelCatalog',
      callback: data => {

        data.key = data.id||'';
        data.title = data.name||'';
        data.children = data.subCatalogs||[];

        let defaultItem = null;

        function recursion(subCatalogs) {

          if ((subCatalogs||[]).length===0) return;

          (subCatalogs||[]).forEach(catalog=> {
            catalog.key = catalog.id||'';
            catalog.title = catalog.name||'';
            catalog.children = catalog.subCatalogs||[];

            if (catalog.id === defaultSelectedId) {
              defaultItem = catalog;
            }

            recursion(catalog.subCatalogs);
          })
        } 

        recursion(data.subCatalogs);
        setLoading(false);
        setTreeData(data.subCatalogs||[]);
        setRootId(data.id||'');

        if (defaultItem) {
          const _dataList = [];
          generateList(data.subCatalogs||[], _dataList);

          const expandedKeys = _dataList
            .map(item => {
              if (item.key.indexOf(defaultSelectedId) > -1) {
                return getParentKey(item.key, data.subCatalogs||[]);
              }
              return null;
            })
            .filter((item, i, self) => item && self.indexOf(item) === i);

          setExpandedKeys(expandedKeys);
          setAutoExpandParent(true);

          setItem(defaultItem);
          onSelect && onSelect(defaultItem.key||'', offset);
        
        } else if (refrence === '') {
          
          const currentItem = (data.subCatalogs||[]).length>0?data.subCatalogs[0]: null;

          setItem(currentItem);
          onSelect && onSelect(currentItem?(currentItem.key||''):'');
          
        }
      },
      error: () => {
        setLoading(false);
      }
    })
  }

  const getStateTreeData = () => {
    setLoading(true);
    dispatch({
      type: 'datamodel.loadDataModelStateCatalog',
      callback: data => {
        setLoading(false);
        let _treeData = data?.subCatalogs||[];
        _treeData.forEach(item => {
          item.title = item.cnName;
          item.key = item.id; 
        })

        setTreeData(_treeData);
        setItem(_treeData.length>0?_treeData[0]:{});
        onSelect && onSelect(_treeData.length>0?_treeData[0].key:'');
      },
      error: () => {
        setLoading(false);
      }
    });
  }

  const getRequirementTreeData = (defaultSelectedId='') => {
    setLoading(true);
    dispatch({
      type: 'datamodel.requirementList',
      payload: {
        techType: 'dataModeler',
      },
      callback: data => {
        setLoading(false);
        let _treeData = [];

        let defaultItem = null;
        data?.forEach(item => {
          const newItem = {title: item.requireName, key: item.id, name: item.requireName};
          _treeData.push(newItem); 
          if (item.id === parseInt(defaultSelectedId)) {
            defaultItem = newItem;
          }
        });

        setTreeData(_treeData);
        if (defaultItem) {
          setItem(defaultItem);
          onSelect && onSelect(defaultItem.key);
        } else {
          setItem(_treeData.length>0?_treeData[0]:{});
          onSelect && onSelect(_treeData.length>0?_treeData[0].key:'');
        }
    
      },
      error: () => {
        setLoading(false);
      }
    });
  }

  const generateList = (treeData, list) => {
    for (let i = 0; i < treeData.length; i++) {
      const node = treeData[i];
      const { id, name } = node;
      list.push({ key: id , title: name });
      if (node.children) {
        generateList(node.children, list);
      }
    }
  };

  const getParentKey = (key, tree) => {
    let parentKey;
    for (let i = 0; i < tree.length; i++) {
      const node = tree[i];
      if (node.children) {
        if (node.children.some(item => item.id === key)) {
          parentKey = node.id;
        } else if (getParentKey(key, node.children)) {
          parentKey = getParentKey(key, node.children);
        }
      }
    }
    return parentKey;
  };

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

  const onViewClick = ({ key }) => {

    if (viewSelectedKey &&  viewSelectedKey===key ) return;

    setViewSelectedKey(key);
    onViewChange && onViewChange(key);

    if (key === 'dir') {
      getDirTreeData();
    } else if (key === 'state') {
      getStateTreeData();
    } else {
      getRequirementTreeData();
    }
  }

  const onSyncMenuClick = ({ key }) => {

    setDomainSelectedKey(key);
    dispatch({
      type: 'datamodel.setRootDomainId',
      payload: {
        params: {
          domainId: key
        }
      },
      callback: () => {
        setIsSetRootId(true);
        getDirTreeData('', null, 'load');
      }
    });

  }

  const onTreeSelect = (keys,data) => {

    if ((keys||[]).length === 0) {
      return;
    }

    const _item = {...data.selectedNodes[0]||[]};

    setItem(_item);
    onSelect && onSelect(_item.key);
  }

  const add = () => {
    setVisible(true);
    setType('add');
  }

  const update = () => {
    setVisible(true);
    setType('update');
  }

  const refresh = () => {
    if (viewSelectedKey==='dir') {
      getDirTreeData(item?.key||'');
    } else if (viewSelectedKey === 'state') {
      getStateTreeData(item?.key||'');
    } else {
      getRequirementTreeData(item?.key||'');
    }
  }

  const sync = () => {
    getDirTreeData(item?.key||'', null, 'load');
  }

  const moveNode = (steps) => {
    setLoading(true);
    dispatch({
      type: 'datamodel.upDownModelCatalog',
      payload: {
        modelCatalogId: currentRightClickDir.id,
        steps
      },
      callback: () => {
        showMessage('success', (steps===-1)?'上移目录成功':'下移目录成功');
        getDirTreeData(item.id);
      }, 
      error: () => {
        setLoading(false);
      }
    });
  }

  const deleteNode = () => {
    modal.confirm({
      title: '提示!',
      content: '删除目录会删除相关的模型,您确定删除吗?',
      onOk: () => {
        setLoading(true);
        dispatch({
          type: 'datamodel.deleteDataModelCatalog',
          payload: {
            params: {
              easyDataModelerCatalogId: currentRightClickDir.id
            }
          },
          callback: () => {
            showMessage('success', '删除目录成功');

            if (item && currentRightClickDir && item.id===currentRightClickDir.id) {
              getDirTreeData();
            } else {
              getDirTreeData(item.id);
            }
          }, 
          error: () => {
            setLoading(false);
          }
        });
      }
    });

  }

  const onUpdateTreeItemModalOk = (id, updateItem) => {
    setVisible(false);
    getDirTreeData(id);
  }

  const onUpdateTreeItemModalCancel = () => {
    setVisible(false);
  }

  const displayMenu = (e) => {
    show(e, {
      position: {
        x: e.clientX + 30,
        y: e.clientY - 10
      }
    });
  }

  const exportMenu = (
    <Menu selectedKeys={[viewSelectedKey]} onClick={onViewClick}>
    {
      viewModes && viewModes.map(item => {
        return (
          <Menu.Item key={item.key} value={item.key} >
            <div style={{ textAlign: 'center' }}>
            {item.name}
            </div>
          </Menu.Item>
        )
      })
    }
    </Menu>
  );

  const syncMenu = (
    <Menu selectedKeys={[domainSelectedKey]} onClick={onSyncMenuClick}>
    {
      domains && domains.map(domain => {
        return (
          <Menu.Item key={domain.domainId} value={domain.domainId} >{domain.domainName}</Menu.Item>
        )
      })
    }
    </Menu>
  );

  const classes = classnames('model-tree', {
    'model-tree-recatalog': (refrence === 'recatalog')
  });  

  return (
    <div className={classes}>
    {
      (refrence==='') && <div
        className='p-3'
        style={{
          display: 'flex',
          borderBottom: "1px solid #EFEFEF",
          height: 57,
          alignItems: 'center',
          justifyContent: (viewSelectedKey==='dir')?'space-between':'',
        }}
      >
        <Dropdown overlay={exportMenu} placement="bottomLeft">
          <Tooltip title="视角">
            <UnorderedListOutlined className='default' style={{ fontSize:16,cursor:'pointer' }} />
          </Tooltip>
        </Dropdown>

        {
          viewSelectedKey==='dir' && ( 
            <Tooltip title="新增目录" className='ml-2'>
              <PlusOutlined className='default' onClick={add} style={{ fontSize:16,cursor:'pointer' }} />
            </Tooltip>
          )
        }     
        {
          viewSelectedKey==='dir' && ( 
            <Tooltip title="存量模型导入" className='ml-2'>
              <ImportOutlined className='default' onClick={() => { importStockModel && importStockModel() }} style={{ fontSize:16,cursor:'pointer' }} />
            </Tooltip>
          )
        }

        <Tooltip title="刷新目录" className='ml-2'>
          <Button type='text' icon={<ReloadOutlined className='default' />} size='small' onClick={refresh} />
        </Tooltip>

        {
          (viewSelectedKey==='dir') && !isSetRootId && (
            <Dropdown overlay={syncMenu} placement="bottomLeft"> 
              <Tooltip title="同步目录">
                <SyncOutlined className='default ml-2' style={{ fontSize:16,cursor:'pointer' }} />
              </Tooltip>
            </Dropdown>
          )
        } 

        {
          (viewSelectedKey==='dir') && isSetRootId && (
              <Tooltip title="同步目录" className='ml-2'>
                <Button type='text' icon={<SyncOutlined className='default' />} size='small' onClick={sync} />
              </Tooltip>
          )
        }   
      </div>
    }
      <div className='p-3'>
        <Spin spinning={loading} >
          <Tree 
            onExpand={onExpand}
            expandedKeys={expandedKeys}
            autoExpandParent={autoExpandParent}
            showLine 
            showIcon={false} 
            onSelect={onTreeSelect} 
            treeData={treeData} 
            selectedKeys={[item?item.key:'']} 
            titleRender={(nodeData) => {
              return <span title={nodeData?.remark||''}>{nodeData?.name||''}</span>;
            }}
            onRightClick={({event, node}) => {
              if (viewSelectedKey==='dir') {
                setCurrentRightClickDir(node);
                displayMenu(event);
              }
            }}
          />      
        </Spin>
      </div>
      <UpdateTreeItemModal 
        visible={visible} 
        type={type}
        item={(type==='add')?item:currentRightClickDir}
        rootId={rootId}
        onOk={onUpdateTreeItemModalOk} 
        onCancel={onUpdateTreeItemModalCancel} 
        />
      {
        (refrence!=='recatalog') && <RcMenu id={MENU_ID}>
          <RcItem id="edit" onClick={update}>
            修改目录
          </RcItem>
          <RcItem id="up" onClick={() => { moveNode(-1); }}>
            上移目录
          </RcItem> 
          <RcItem id="down" onClick={() => { moveNode(1); }}>
            下移目录
          </RcItem> 
          <RcItem id="delete" onClick={deleteNode}>
            删除目录
          </RcItem>
        </RcMenu> 
      } 
      {contextHolder}  
    </div>
  );
}

export default ModelTree;