import React, { useEffect, useState, useRef } from 'react';
import {Card, Spin, Tooltip, Tree, Modal, AutoComplete, Select,Button, Menu, Dropdown, Space} from 'antd';
import { ReloadOutlined, SettingOutlined, UnorderedListOutlined } 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, getAssetRange } from '../../../../util';
import { AnchorTimestamp, AnchorId, AssetBrowseReference, ResourceBrowseReference, AnchorDirId, AnchorTemplateType } from '../../../../util/constant';
import { highlightSearchContentByTerms } from '../../../../util';
import UpdateDirectoryModal from './UpdateDirectoryModal';

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

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, getDirs } = 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 [ updateDirectoryAction, setUpdateDirectoryAction ] = useState('');
  const [ updateDirectoryModalVisible, setUpdateDirectoryModalVisible ] = useState(false);
  const [ viewSelectedKey, setViewSelectedKey ] = useState(viewModes[0].key);

  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([]);
  const viewSelectedKeyRef = useRef(viewModes[0].key)

  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])

  useEffect(() => {
    getDirs?.(treeData)
  }, [treeData])

  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) {
          const _templateType = getQueryParam(AnchorTemplateType, props?.location?.search)
          const _dirId = getQueryParam(AnchorDirId, props?.location?.search)

          if (_templateType) {
            setTemplateType(_templateType)
            LocalStorage.set(`templateType-${appId}`, _templateType)
            listSubject.next({ msg: 'templateChange' })
          } else {
            setTemplateType(data[0].type)
            LocalStorage.set(`templateType-${appId}`, data[0].type)
            listSubject.next({ msg: 'templateChange' })
          }

          if (_dirId) {
            getAllDirectoryAsTree(true, _dirId)
          } else {
            onSelect?.('', '', false)
            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 = 'assetmanage.queryAllDirectoryAsTree';
    if (viewSelectedKeyRef.current === 'custom') {
      url = 'assetmanage.queryCustomTypeRootDirectory';
    }
    
    dispatch({
      type: url,
      payload: {
        range: getAssetRange(AssetBrowseReference)
      },
      callback: data => {
        setLoading(false);
        refresh && showMessage('success', '操作成功');

        let newData = [];
        if (viewSelectedKeyRef.current==='dir') {
          newData = [...data];
        } else {
          newData = (data||[]).map((item) => {
            return {...item, text: item.name, nodeId: item.id, type: item.resourceType}
          });
        }

        setLoadedKeys([]);
        setTreeData(newData);

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

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

        let defaultItem = null;

        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);
            setAutoExpandParent(true);
  
            setCurrentDirId(defaultItem.nodeId);
            onSelect && onSelect(defaultItem.nodeId, defaultItem.type||'', defaultItem.level, defaultItem.allowdLoadDataAsset);
          
          } else if ((newData??[]).length > 0) {
            defaultItem = newData[0]
            setCurrentDirId(defaultItem.nodeId);
            onSelect && onSelect(defaultItem.nodeId, defaultItem.type||'', defaultItem.level, defaultItem.allowdLoadDataAsset);
          } else {
            onSelect && onSelect('', '')
          }
        }
      },
      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||'', defaultItem.allowdLoadDataAsset);
    } 
  }

  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,
                currentDirIsCustom: currentRightClickDir.type==='custom'
              }
            },
            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, { node }) => {
    if ((keys||[]).length === 0) {
      return;
    }

    setCurrentDirId(keys[0]);

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

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

  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 onDetailClick = () => {
    setUpdateDirectoryAction('detail');
    setUpdateDirectoryModalVisible(true);
  }

  const displayMenu = (event) => {
    show(event, {
      position: {
        x: event.clientX + 30,
        y: event.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 onViewClick = ({ key }) => {
    if (viewSelectedKey &&  viewSelectedKey===key ) return;

    viewSelectedKeyRef.current = key;
    setViewSelectedKey(key);
    setExpandedKeys([]);
    
    getAllDirectoryAsTree();
  }  

  const viewMenus = (
    <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 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} <span>{item?.dataAssetAndSubDirCount?`(${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={ 
        <Space
          style={{
            height: 57,
            padding: '0 15px'
          }}
        >
          <Select 
            size='small'
            loading={loadingTemplates}
            value={currentTemplateType}
            onChange={(val) => {
              setTemplateType(val)
              LocalStorage.set(`templateType-${appId}`, val);
              listSubject.next({ msg: 'templateChange' });
              setCurrentDirId();
              getAllDirectoryAsTree(true)
            }}
            style={{ width: 100 }}
          >
          {
            (templates??[]).map((item, index) => <Select.Option key={index} value={item.type}>{item.name}</Select.Option>)
          }
          </Select>
          <Dropdown overlay={viewMenus} placement="bottomLeft">
            <Tooltip title="视角">
              <UnorderedListOutlined className='default' style={{ fontSize:16,cursor:'pointer' }} />
            </Tooltip>
          </Dropdown>
          <Tooltip title="刷新目录">
            <ReloadOutlined className='default' onClick={refreshTree} style={{ fontSize:16,cursor:'pointer'}} />
          </Tooltip>
        </Space>
      }
      bordered={false} 
      bodyStyle={{ padding: '10px 15px' }}
      headStyle={{ padding: 0 }}
      style={{ width: '100%' }} 
    >
      <Spin spinning={loading}>
        {
          viewSelectedKeyRef.current === 'dir' && <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}) => {
            setCurrentRightClickDir(node);
            displayMenu(event);
          }}
          />
      </Spin>

      <UpdateDirectoryModal 
        visible={ updateDirectoryModalVisible }
        onCancel={() => {
          setUpdateDirectoryAction()
          setUpdateDirectoryModalVisible(false)
        }}
        action={ updateDirectoryAction }
        dirId={ currentRightClickDir?.nodeId }
      />

      <CustomDirectoryModal 
        visible={ customDirectoryModalVisible }
        onCancel={ onCustomDirectoryCancel }
        action={ customDirectoryAction }
        reference={ reference }
        dirId= { currentDirId }
      />
      {
        <RcMenu id={MENU_ID}>
        {
          currentRightClickDir && (currentRightClickDir.type!=='custom') && <RcItem id="detail" onClick={onDetailClick}>
          { (currentRightClickDir.level===1)?'栏目详情':'目录详情' }
          </RcItem>
        }
        </RcMenu> 
      } 
      {contextHolder}
    </Card>
  )
}

export default AssetTree;