import React, { useEffect, useState, useRef } from 'react';
import {Card, Spin, Tooltip, Tree, Modal, AutoComplete, Select} from 'antd';
import { ReloadOutlined, SettingOutlined } from '@ant-design/icons';
import { useContextMenu, Menu as RcMenu, Item as RcItem } from "react-contexify";
import LocalStorage from 'local-storage';

import { dispatch } from '../../../../model';
import CustomDirectoryModal from './CustomDirectoryModal';
import { showMessage, getQueryParam } from '../../../../util';
import { AnchorTimestamp, AnchorId, AssetBrowseReference, ResourceBrowseReference, AnchorDirId } from '../../../../util/constant';
import { highlightSearchContentByTerms } from '../../../../util';

import './AssetTree.less';
import 'react-contexify/dist/ReactContexify.css';
import { appId } from '../../../../App';

const { Option } = AutoComplete;

function updateTreeData(list, key, children) {
  return list.map((node) => {
    if (node.nodeId === key) {
      return { ...node, children };
    }

    if (node.children) {
      return {
        ...node,
        children: updateTreeData(node.children, key, children),
      };
    }

    return node;
  });
}

const AssetTree = (props) => {

  const MENU_ID = 'asset-tree';

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

  const { onSelect, onCheck, tableId, reference=AssetBrowseReference, centerId } = props; 
  const [ keyword, setKeyword ] = useState('');
  const [ loading, setLoading ] = useState(false);
  const [ treeData, setTreeData ] = useState([]);
  const [ dataList, setDataList ] = useState([]);
  const [ expandedKeys, setExpandedKeys ] = useState([]);
  const [ autoExpandParent, setAutoExpandParent ] = useState(false);
  const [ currentDirId, setCurrentDirId ] = useState('');
  const [ currentRightClickDir, setCurrentRightClickDir ] = useState({});
  const [ customDirectoryModalVisible, setCustomDirectoryModalVisible ] = useState(false);
  const [ customDirectoryAction, setCustomDirectoryAction ] = useState('');
  const [options, setOptions] = useState([]);
  const [ loadedKeys, setLoadedKeys ] = useState([]);
  const [loadingTemplates, setLoadingTemplates] = useState(false)
  const [templates, setTemplates] = useState()
  const [currentTemplateType, setTemplateType] = 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 treeDataRef = useRef([]);
  const dataListRef = useRef([]);

  useEffect(() => {
    getTemplates()
    window?.addEventListener("storage", storageChange);

    return () => {
      window?.removeEventListener("storage", storageChange);
    }

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

  // useEffect(() => {
  //   if ((did||'') !== '') {
  //     getAllDirectoryAsTree(true, did);
  //   } else if ((id||'') !== '') {
  //     getDataAssetLocationThenGetTreeData();
  //   }  else {
  //     getAllDirectoryAsTree(true);
  //   } 
  //   //eslint-disable-next-line react-hooks/exhaustive-deps
  // }, [timestamp])

  useEffect(() => {
    if ((tableId||'') !== '') {
      getTableDirIds();
    } 
    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [tableId])

  useEffect(() => {
    if ((centerId||'')!=='' && centerId!==currentDirId) {
      treeDirectoryChanged(centerId);
    } 
    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [centerId])

  const storageChange = (e) => {
    if (e.key === 'assetDirChangeEvent') {
      if ((e.dirId||'') !== '') {
        treeDirectoryChanged(e.dirId);
      }
    } else if (e.key === 'assetRelationOnClickEvent') {
      treeDirectoryChanged(e.relation?.dirId);
    }
  }

  const getTemplates = () => {
    setLoadingTemplates(true)
    dispatch({
      type: 'assetmanage.getTemplates',
      callback: data => {
        setLoadingTemplates(false)
        setTemplates(data)
        if ((data??[]).length > 0) {
          setTemplateType(data[0].type)
          const _templateType = getQueryParam('templateType', props?.location?.search)
          const _dirId = getQueryParam(AnchorDirId, props?.location?.search)

          if (_templateType) {
            LocalStorage.set(`templateType-${appId}`, _templateType)
          } else {
            LocalStorage.set(`templateType-${appId}`, data[0].type)
          }

          let event = new Event('storage');
          event.key = 'assetTemplateChange';
          window?.dispatchEvent(event);

          if (_dirId) {
            getAllDirectoryAsTree(true, _dirId)
          } else {
            onSelect?.('', '')
            getAllDirectoryAsTree(true)
          }
        }
      },
      error: () => {
        setLoadingTemplates(false)
      }
    })
  }

  const getDataAssetLocationThenGetTreeData = () => {
    setLoading(true);
    dispatch({
      type: 'assetmanage.getDataAssetLocation',
      payload: {
        dataAssetId: id
      },
      callback: data => {
        getAllDirectoryAsTree(true, data.dirId||'');
      },
      error: () => {
        setLoading(false);
        getAllDirectoryAsTree(true);
      }
    });
  }

  const getTableDirIds = () => {
    dispatch({
      type: 'assetmanage.getDataAssetDetail',
      payload: {
        dataAssetId: tableId
      },
      callback: data => {
        setExpandedKeys(data.dirIds||[]);
        setAutoExpandParent(true);
        onCheck && onCheck(data.dirIds||[]);
      },
    })
  }

  const getAllDirectoryAsTree = (resetCurrentDirId=true, defaultSelectedId='', refresh = false) => {

    setLoading(true);
    // if (resetCurrentDirId) {
    //   onSelect && onSelect('', '');
    // }

    let url = '';
    if (reference === AssetBrowseReference) {
      url = 'assetmanage.queryAssetDirectoryAsTree';
    } else if (reference === ResourceBrowseReference) {
      url = 'assetmanage.queryResourceDirectoryAsTree';
    }
    
    dispatch({
      type: url,
      callback: data => {
        setLoading(false);
        refresh && showMessage('success', '操作成功');

        let newData = [...data];

        setLoadedKeys([]);
        setTreeData(newData);

        const _dataList = [], _groupIds = [];
        generateList(newData, _dataList);
        generateGroupIds(newData, _groupIds);
        setDataList(_dataList);

        treeDataRef.current = newData;
        dataListRef.current = _dataList;

        let defaultItem = null;

        if ((defaultSelectedId||'') === '') {
          _dataList.forEach(item => {
            if ((defaultSelectedId||'')==='') {
              defaultSelectedId = item.key;
            }
          })
        }

        function recursion(subCatalogs) {

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

          (subCatalogs||[]).forEach(catalog=> {
    
            if (catalog.nodeId === defaultSelectedId) {
              defaultItem = catalog;
            }

            recursion(catalog.children);
          })
        } 

        if ((defaultSelectedId||'') !== '') {
          recursion(newData);
        }

        if (resetCurrentDirId) {

          if (defaultItem) {  
            const expandedKeys = _dataList
              .map(item => {
                if (item.key.indexOf(defaultSelectedId) > -1) {
                  return getParentKey(item.key, newData);
                }
                return null;
              })
              .filter((item, i, self) => item && self.indexOf(item) === i);
            
            setExpandedKeys([...expandedKeys, defaultSelectedId]);
            setAutoExpandParent(true);
  
            setCurrentDirId(defaultItem.nodeId);
            onSelect && onSelect(defaultItem.nodeId, defaultItem.type||'');
          
          } 
       
        }
      },
      error: () => {
        setLoading(false);
      }
    });
  }

  const treeDirectoryChanged = (did) => {

    let defaultItem = null;

    function recursion(subCatalogs) {

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

      (subCatalogs||[]).forEach(catalog=> {

        if (catalog.nodeId === did) {
          defaultItem = catalog;
        }

        recursion(catalog.children);
      })
    } 

    if ((did||'') !== '') {
      recursion(treeDataRef.current);
    }

    if (defaultItem) {  
      const expandedKeys = (dataListRef.current||[])
        .map(item => {
          if (item.key.indexOf(did) > -1) {
            return getParentKey(item.key, treeDataRef.current);
          }
          return null;
        })
        .filter((item, i, self) => item && self.indexOf(item) === i);

      setExpandedKeys([...expandedKeys,did]);
      setAutoExpandParent(true);

      setCurrentDirId(defaultItem.nodeId);
      onSelect && onSelect(defaultItem.nodeId, defaultItem.type||'');
    } 
  }

  const generateList = (treeData, list, path = null) => {
    for (let i = 0; i < treeData.length; i++) {
      const node = treeData[i];

      if (node.resourceType !== 'custom') {

        const { nodeId, text } = node;

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

  const generateGroupIds = (treeData, list) => {
    
    function generateGroupItem(data, list) {
      for (let i = 0; i < data.length; i++) {
        const node = data[i];
        list.push(node.nodeId);
        if (node.children) {
          generateGroupItem(node.children, list);
        }
      }
    }
   
    for (let i = 0; i < treeData.length; i++) {
      const node = treeData[i];
      const { nodeId } = node;

      const groupItem = [nodeId];
      if (node.children) {
        generateGroupItem(node.children, groupItem);
      }

      list.push(groupItem);
    }

  };

  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.nodeId === key)) {
          parentKey = node.nodeId;
        } else if (getParentKey(key, node.children)) {
          parentKey = getParentKey(key, node.children);
        }
      }
    }
    return parentKey;
  };

  const getCurrentType = (key, tree) => {
    let type = '';

    (tree||[]).forEach(node => {
      if (node.nodeId === key) {
        type = node.type||'';        
      } else if (node.children) {
        if (getCurrentType(key, node.children)) {
          type = getCurrentType(key, node.children);
        }
      }
    })
    
    return type;
  }

  const refreshTree = () => {
    getAllDirectoryAsTree(false, '', true);
  }

  const deleteDir = () => {    
    if (currentRightClickDir.nodeId) {
      modal.confirm({
        title: '您确定要删除该目录吗?',
        onOk: () => {
          dispatch({
            type: 'assetmanage.checkDirectoryDeleteAble',
            payload: {
              params: {
                dirId: currentRightClickDir.nodeId
              }
            },
            callback: able => {
              if (able === 'true') {
                dispatch({
                  type: 'assetmanage.deletePersonalCustomDirectory',
                  payload: {data: [ currentRightClickDir.nodeId ]},
                  callback: () => {
                    showMessage("success","删除成功");
                    getAllDirectoryAsTree(true, currentDirId);
                  }
                })
              } else {
                showMessage("warn","目录下有资产目录信息,不允许删除!");
              }
            }
          })
        }
      })

    } else {
      showMessage('info', '请先选择目录');
    }
  }

  const moveNode = (steps) => {
    if ((currentRightClickDir.nodeId||'') === '') {
      showMessage('info', '请先选择目录');
      return;
    }

    setLoading(true);
    dispatch({
      type: 'assetmanage.upDownPersonalCustomDirectory',
      payload: {
        params: {
          dirId: currentRightClickDir.nodeId,
          steps
        }
      },
      callback: () => {
        showMessage('success', (steps===1)?'上移目录成功':'下移目录成功');
        getAllDirectoryAsTree(false);
      }, 
      error: () => {
        setLoading(false);
      }
    });
  }

  const customDir = () => {
    setCustomDirectoryAction('add');
    setCustomDirectoryModalVisible(true);
  }

  const onTreeSelect = (keys, _) => {

    if ((keys||[]).length === 0) {
      // setCurrentDirId();
      // onSelect?.('', '');
      return;
    }

    setCurrentDirId(keys[0]);

    const _currentDirType = getCurrentType(keys[0], treeData);

    onSelect && onSelect(keys[0], _currentDirType);
  }

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

  const onCustomDirectoryCancel = (refresh=false, id='') => {
    setCustomDirectoryModalVisible(false);
    if (refresh) {
      if (customDirectoryAction === 'add') {
        getAllDirectoryAsTree(true, id);
      } else {
        getAllDirectoryAsTree(false);
      }
    }
  }

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

  const onAutoCompleteSearch = (searchText) => {
    setKeyword(searchText);
    setOptions(
      !searchText ? [] : (dataList||[]).filter(item => item.value.indexOf(searchText)!==-1),
    );
  };

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

  const onLoadData = ({ key, children }) => 
    new Promise((resolve) => {

      if (children) {
        resolve();
        return;
      }

      setLoadedKeys([...loadedKeys, key]);

      dispatch({
        type: 'assetmanage.getPersonalCustomDirecotryChild',
        payload: {
          parentId: key,
        },
        callback: (data) => {
          if (data && data.length>0) {
            let newTreeData = updateTreeData(treeData, key, data);
            setTreeData(newTreeData);
            treeDataRef.current = newTreeData;
          }
      
          resolve();
        }, 
        error: () => {
          resolve();
        }
      });
    });

  const loop = (data, rootResourceType = null) =>
    data.map(item => {

      if (item.level === 1) {
        rootResourceType = item.type;
      }

      const title = (
        <span
          className={(item.level===1)?'title-color': 'text-color'}
        >
          {item.text}
          {
            (item.level!==1||(item.level===1&&item.resourceType!=='custom')) && <span>{` (${item.dataAssetAndSubDirCount})`}</span>
          }
        </span>
      );

      if (item.children && item.children.length>0) {
        return { ...item, ...{ title, key: item.nodeId, children: loop(item.children, rootResourceType) }};
      }

      if (rootResourceType !== 'custom') {
        return { ...item, ...{ title, key: item.nodeId, isLeaf: true }};
      }

      return { ...item, ...{ title, key: item.nodeId, children: null }};
    });

  return (
    <Card
      className='asset-tree'
      title={ 
        <div
          className='flex'
          style={{
            height: 57,
            alignItems: 'center',
            justifyContent: 'space-between',
            padding: '0 15px'
          }}
        >
          <Select 
            size='small'
            loading={loadingTemplates}
            value={currentTemplateType}
            onChange={(val) => {
              setTemplateType(val)
              LocalStorage.set(`templateType-${appId}`, val);
              let event = new Event('storage');
              event.key = 'assetTemplateChange';
              window?.dispatchEvent(event);

              setCurrentDirId();
              onSelect?.(null, null);
              setTimeout(() => {
                onSelect?.('', '');
                getAllDirectoryAsTree(true)
              }, 100)
            }}
            style={{ width: 100 }}
          >
          {
            (templates??[]).map((item, index) => <Select.Option key={index} value={item.type}>{item.name}</Select.Option>)
          }
          </Select>
          <Tooltip title="刷新目录">
            <ReloadOutlined className='default' onClick={refreshTree} style={{ fontSize:16,cursor:'pointer',flex:1}} />
          </Tooltip>
          {/* <Tooltip title="自定义目录">
            <SettingOutlined className='default' onClick={customDir} style={{ fontSize:16,cursor:'pointer',flex:1}} />
          </Tooltip> */}
          <div style={{ flex: 3 }}></div>
        </div>
      }
      bordered={false} 
      bodyStyle={{ padding: '10px 15px' }}
      headStyle={{ padding: 0 }}
      style={{ width: '100%' }} 
    >
      <Spin spinning={loading}>
        <AutoComplete
          allowClear
          value={keyword}
          style={{ marginBottom: 10, width: '100%' }}
          placeholder='搜索目录'
          onSelect={onAutoCompleteSelect}
          onSearch={onAutoCompleteSearch}
          onClear={() => { setKeyword(''); }}
          notFoundContent={keyword?<span>暂无数据</span>:null}
        >
        {
          (options||[]).map((item, index) => {
            return (
              <Option key={item.key} value={item.value}>
                <div style={{ whiteSpace: 'normal' }}>
                {highlightSearchContentByTerms(item.value, [keyword])}
                </div>
              </Option>
            );
          })
        }
        </AutoComplete>
        <Tree
          showLine={true}
          showIcon={false}
          onExpand={onExpand}
          expandedKeys={expandedKeys}
          autoExpandParent={autoExpandParent}
          treeData={loop(treeData)}
          loadData={onLoadData}
          loadedKeys={loadedKeys}
          selectedKeys={[currentDirId||'']} 
          onSelect={onTreeSelect} 
          checkStrictly
          onRightClick={({event, node}) => {
            if (node.level>1 && node.type==='custom') {
              setCurrentRightClickDir(node);
              displayMenu(event);
            }
          }}
          />
      </Spin>

      <CustomDirectoryModal 
        visible={ customDirectoryModalVisible }
        onCancel={ onCustomDirectoryCancel }
        action={ customDirectoryAction }
        reference={ reference }
        dirId= { currentDirId }
      />
      {
        <RcMenu id={MENU_ID}>
        {
          currentRightClickDir && currentRightClickDir.level>1 && currentRightClickDir.type==='custom' && <RcItem id="up" onClick={() => { moveNode(1); }}>
          上移目录
          </RcItem> 
        }
        {
          currentRightClickDir && currentRightClickDir.level>1 && currentRightClickDir.type==='custom' && <RcItem id="up" onClick={() => { moveNode(-1); }}>
          下移目录
          </RcItem> 
        }
        {
          currentRightClickDir && currentRightClickDir.level===2 && currentRightClickDir.type==='custom' && !currentRightClickDir.adminCreate && <RcItem id="up" onClick={deleteDir}>
          删除目录
          </RcItem> 
        }
        </RcMenu> 
      } 
      {contextHolder}
    </Card>
  )
}

export default AssetTree;