import React, { useState } from 'react';
import { Tree, Dropdown, Menu, message, Modal, Input } from 'antd';
import DelModal from '../../components/ModalFun';
import './index.scss';
import '../../components/ModalFun/index.scss';
import { deleteWiki, findNodeByChildrenKey, findNodeByKey, getWiki, treeToMd, updateWiki } from '../../api';
import { useEffect } from 'react';
import { Base64 } from 'js-base64';
const Search = Input.Search;
const {DirectoryTree, TreeNode} = Tree;

// wiki目录树
export default function Sidebar(props) {
  const {fileList, changeitem, owner, projectsId, project, setReload, sidebar, history, permission, defaultSelectedKeys, fileArrInit} = props;
  const {location:{pathname}} = history;
  const [initMenuList, setInitMenuList] = useState(undefined);
  const [menuList, setMenuList] = useState(undefined);
  const [actionVisible, setActionVisible] = useState(undefined);
  const [visible, setVisible] = useState(false);
  const [menuName, setMenuName] = useState(undefined);
  const [addMenuError, setAddMenuError] = useState(undefined);
  const [selectedKey, setSelectedKey] = useState(undefined);
  const [expandedKeys, setExpandedKeys] = useState(undefined);
  // 是否全部展开
  const [isExpendedAll, setIsExpendedAll] = useState(false);
  // 重命名目录名称
  const [isEditName, setIsEditName] = useState(undefined);
  // wiki重命名-wiki内容
  const [wikiContent, setWikiContent] = useState(undefined);

  useEffect(()=>{
    if(defaultSelectedKeys){
      // 设置选中wiki
      setSelectedKey(defaultSelectedKeys);
      // 第一次渲染，默认打开选中的页面所处目录
      const keys = expandedKeys || [];
      const list = defaultSelectedKeys[0].split('-');
      list.map((item, index)=>{
        keys.push(index > 0 ? `${keys[index-1]}-${item}` : item)
      })
      setExpandedKeys(Array.from(new Set(keys)));
    }
  }, [defaultSelectedKeys])

  useEffect(()=>{
    setMenuList(fileList);
    setInitMenuList(fileList);
  }, [fileList])

  const menu = (title, isFile, item, level) =>{
    return <Menu>
      <Menu.Item>
        <a onClick={(e) => { addFile(e, item) }}>
          添加子页面
        </a>
      </Menu.Item>
      <Menu.Item>
        <a onClick={(e) => {e.stopPropagation();setVisible(item);}}>
          添加子目录
        </a>
      </Menu.Item>
      <Menu.Item>
        <a onClick={(e) => { updateName(e, item, 1) }}>
          重命名
        </a>
      </Menu.Item>
      <Menu.Item>
        <a onClick={(e) => { deleteFileModal(e, title, isFile, item) }}>
          删除
        </a>
      </Menu.Item>
    </Menu>
  };

  const fileMenu = (title, isFile, item) =>{
    return <Menu>
      <Menu.Item>
        <a onClick={(e) => { updateName(e, item, 2) }}>
          重命名
        </a>
      </Menu.Item>
      <Menu.Item>
        <a onClick={(e) => { deleteFileModal(e, title, isFile, item) }}>
          删除
        </a>
      </Menu.Item>
    </Menu>
  };

  const treeTitle = (title, isFile, key, item, level)=>{
    return <React.Fragment>
      <span className='wikiName font-15'>{title}</span>
      {permission && <span className= {actionVisible === key ? 'visibleIcon wikiActionBox' : 'wikiActionBox'}>
        <Dropdown overlay={isFile ? fileMenu(title, isFile, item) : menu(title, isFile, item, level)} placement="bottomRight" onVisibleChange={(value)=>{setActionVisible(value ? key : undefined)}}>
          <i className="iconfont icon-kongbai font-14"></i>
        </Dropdown>
      </span>}
    </React.Fragment>
  }

  function renderTreeNodes(data) {
    return data && data.length > 0 && data.map((item) => {
      const level = item.title.search(/\S/);
      let title = item.title.trim();
      const isFile = title.startsWith('[[') && title.endsWith(']]');
      title = isFile ? title.substring(2,title.length-2) : title.substring(2, title.length);
      return (
        <TreeNode title={treeTitle(title, isFile, item.key, item, level)} key={item.key+""} isLeaf={isFile} dataRef={item}>
          {renderTreeNodes(item.children)}
        </TreeNode>
      );
    });
  }

  // 遍历list，找到相同的key callback
  const loop = (data, key, callback) => {
    data.forEach((item, index, arr) => {
      if (item.key === key) {
        return callback(item, index, arr);
      }
      if (item.children) {
        return loop(item.children, key, callback);
      }
    });
  };

  // 选中节点
  function selectTree(keys,event){
    let {title, key} = event.node.props.dataRef;
    setSelectedKey([key+""]);
    title = title.trim();
    const isFile = title.startsWith('[[') && title.endsWith(']]');
    if(isFile){
      title = title.substring(2,title.length-2);
      changeitem({name: title, key});
    }
  }

  // 收起展开
  function onExpand(keys, obj){
    const oldKeys = new Set(keys);
    const {expanded} = obj;
    let {key} = obj.node.props.dataRef;
    if(expanded){
      oldKeys.add(key);
    }else{
      oldKeys.delete(key);
    }
    setExpandedKeys(Array.from(oldKeys))
  }

  // 删除wiki模态框
  function deleteFileModal(e, title, isFile, item) {
    e.stopPropagation();
    DelModal({
      title: `删除${isFile ? '页面' : '目录'}`,
      contentTitle: `您确定要删除“${title}”此${isFile ? '页面' : '目录'}吗？`,
      content: `此操作将删除此${isFile ? '页面' : '目录'}，请进行确认以防文件的丢失`,
      onOk: () => {
        const {node, children, key} = item;
        if(isFile){
          // 删除页面
          deleteWiki({owner: owner, repo: projectsId, projectId: project.id, pageName: title}).then(res => {
            if(res && res.message === "204"){
              // 递归过滤相同key值的节点，执行删除操作
              const menuListByDel = findSameKeyByDel(menuList, key);
              updateSidebar(treeToMd(menuListByDel), 1);
            }
          });
        }else{
          // 删除目录（递归找到所有的[[页面]]，遍历删除）
          // needDelNode: 被删除的子节点
          const needDelNode = findNodeByKey(menuList, key);
          // needDelWikis：所有需要删除的子目录列表
          const needDelWikis = [];
          findDelNode(needDelNode.children, needDelWikis);
          if(needDelWikis.length){
            // 有需要删除的子目录
            const promiseList = []
            needDelWikis.map(item=>{
              promiseList.push(deleteWikiFun({owner: owner, repo: projectsId, projectId: project.id},item.title.trim()))
            })
            Promise.all(promiseList).then((values) => {
              if(values.filter(item=>item.message === '204' || item.message === '404').length === needDelWikis.length){
                // 执行修改sidebar操作：递归过滤相同key值的节点，执行删除操作
                const menuListByDel = findSameKeyByDel(menuList, key);
                updateSidebar(treeToMd(menuListByDel), 1);
              }else{
                message.error('发生未知错误，请联系系统管理员')
              }
            });
          }else{
            // 没有需要删除的子目录，直接修改sidebar文件即可
            const menuListByDel = findSameKeyByDel(menuList, key);
            updateSidebar(treeToMd(menuListByDel), 1);
          }
        }
      }
    });
  }

  // 删除页面：递归过滤相同key值的节点
  function findSameKeyByDel(list, key){
    return list.filter(item => {
      if (item.key === key) {
        return false
      }
      if(item.children && item.children.length > 0){
        item.children = findSameKeyByDel(item.children , key)
      }
      return true
    })
  }

  // 删除目录：递归找到需要删除的子目录
  function findDelNode(list, nodes){
    //利用foreach循环遍历
    list.forEach(item => {
      //判断递归结束条件
      const title = item.title.trim();
      if (title.startsWith('[[') && title.endsWith(']]')) {
        // 存储数据到空数组
        nodes.push(item);
      }
      if (item.children.length){
        //递归调用
        const result = findDelNode(item.children, nodes);
        if(result) return result
      }else{
        return true
      }
    })
    return nodes;
  }

  // 删除wiki
  function deleteWikiFun(info, title){
    return new Promise((resolve, reject)=>{
      deleteWiki({
        ...info,
        pageName: title
      }).then(res => {
        resolve(res)
      })
    })
  }

  // 修改此仓库的sidebar文件 type 1删除 2拖拽 3添加子目录 4目录重命名
  function updateSidebar(content, type, addWikiName){
    if(type === 1 && !content){
      // 删除最后一个wiki的时候，同时删除sidebar
      deleteWiki({owner: owner, repo: projectsId, projectId: project.id, pageName: "_Sidebar"}).then(res => {
        if(res && res.message === "204"){
          history.push(`/${owner}/${projectsId}/wiki`)
          setReload(Math.random());
          message.success('删除成功');
        }
      });
      return
    }
    updateWiki({
      owner,
      repo: projectsId,
      projectId: project.id,
      pageName: '_Sidebar',
      title: '_Sidebar',
      commit_message: '',
      content_base64: Base64.encode(content)
    }).then(res => {
      if (res && res.message === "200") {
        setReload(Math.random());
        if(type === 1){
          message.success('删除成功');
        }else if(type === 3){
          setMenuName(undefined);
          setVisible(false);
          message.success('新增成功');
        }else if(type === 4){
          setIsEditName(false);
          setMenuName(undefined);
          setVisible(false);
          message.success('重命名成功');
        }else{
          console.log('修改文件目录顺序成功');
        }
      }
    });
  }

  // 添加子页面
  function addFile(e, item){
    e.stopPropagation();
    history.push(`/${owner}/${projectsId}/wiki/add?key=${item.key}`)
  }

  // 重命名目录文件 type:1 目录 2页面
  function updateName(e, item, type){
    e.stopPropagation();
    setVisible(item);
    setIsEditName(type);
    let title = item.title.trim();
    const isFile = title.startsWith('[[') && title.endsWith(']]');
    title = isFile ? title.substring(2,title.length-2) : title.substring(2, title.length);
    type === 2 && getWiki({
      owner: owner,
      repo: projectsId,
      pageName: title,
      projectId: project.id
    }).then(res => {
      if (res && res.message === "200") {
        setWikiContent(res.data.md_content);
      }
    })
    setMenuName(title);
  }

  // 新增子目录 或者 重命名目录
  function submit(){
    if(!menuName){
      setAddMenuError('请输入目录名称');
      return;
    }
    if(new RegExp("^[ ]+$").test(menuName)){
      setAddMenuError("不能仅输入空格");
      return;
    }
    const regEn = /[\\/:*?"<>|[\]-]/g;
    if (regEn.test(menuName)) {
      setAddMenuError('不能有特殊字符: \\ / : * ? \" < > | [ \] -');
      return;
    }
    if(!isEditName){
      // 新增目录：校验同级目录中是否有相同名称
      const {children, key} = visible;
      const mList = children.filter(item=>!item.title.trim().startsWith('[[')).map(i=>i.title.trim())
      if(mList.includes(`- ${menuName}`)){
        setAddMenuError('不能与已有目录名称相同');
        return;
      }
      const newList = menuList;
      // 设置Tree 打开的目录
      const keys = expandedKeys || [];
      const list = key.split('-');
      list.map((item, index)=>{
        keys.push(index > 0 ? `${keys[index-1]}-${item}` : item)
      })
      keys.push(`${key}-${children.length}`);
      setExpandedKeys(Array.from(new Set(keys)));
      addChildrenByKey(newList, key, menuName);
      updateSidebar(treeToMd(newList), 3);
    }else{
      // isEditName 1 编辑目录名称 2编辑页面名称
      const titleToJudge = isEditName === 2 ? `[[${menuName}]]` : `- ${menuName}`;
      const {children, node, title, key} = visible;
      const list = findNodeByChildrenKey(menuList, key) || [];
      if(title.trim() === titleToJudge){
        setAddMenuError("请修改名称");
        return
      }
      if(list.map(item=>item.title.trim()).includes(titleToJudge)){
        message.error("不能与同级目录名称相同");
        return
      }
      // wiki名称不可重复
      const sameNameWiki = fileArrInit.filter(item=>item.name === menuName)
      if(isEditName === 2 && sameNameWiki.length){
        message.error("wiki名称不可重复");
        return
      }
      // 编辑sidebar
      const newMenuList = JSON.parse(JSON.stringify(menuList))
      loop(newMenuList, key, (item)=>{
        const {key} = item;
        item.title = `${'\t'.repeat(key.split('-').length-1)}${titleToJudge}`
      })
      if(isEditName === 2){
        // 编辑页面名称-> 修改wiki
        const oldTitle = title.substring(title.indexOf('[[')+2, title.indexOf(']]'))
        updateWiki({
          owner,
          repo: projectsId,
          projectId: project.id,
          // 原名称
          pageName: oldTitle,
          // 现名称
          title: menuName,
          content_base64: wikiContent,
          commit_message: '',
        }).then(res=>{
          if(res && res.message === '200'){
            // 修改wiki名称接口请求成功，更新sidebar
            updateSidebar(treeToMd(newMenuList), 4);
            history.push(`/${owner}/${projectsId}/wiki/${encodeURI(menuName)}/${key}`);
          }
        })
        return;
      }
      updateSidebar(treeToMd(newMenuList), 4)
    }
  }

  // 递归menuList 创建子目录
  function addChildrenByKey(list, key, name){
    for (let index = 0; index < list.length; index++) {
      const element = list[index];
      if (element.key == key) {
        const {title} = element;
        element.children.push({
          title: `\t${title.substring(0, title.indexOf('- '))}- ${name}`,
          children: []
        });
        return true;
      }else if (element.children.length) {
        let result = addChildrenByKey(element.children, key, name);
        if (result) {
          return result;
        }
      }
    }
  }


  function onDrop(info){
    // dragNode: 拖拽的节点  node: 放入的节点
    const dropKey = info.node.props.dataRef.key;
    const dragKey = info.dragNode.props.dataRef.key;
    const dropPos = info.node.props.pos.split('-');
    const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]);
    // dropPosition 0元素之上 1元素之下 -1元素之上

    function upTitle(list, title){
      const kongGe = title.substring(0, title.indexOf('- ') === -1 ? title.indexOf('[[') : title.indexOf('- '));
      list.map(item=>{
        item.title = `\t${kongGe}${item.title.trim()}`;
        if(item.children){
          return upTitle(item.children, item.title);
        }
      })
    }

    const data = JSON.parse(JSON.stringify(menuList));

    // Find dragObject
    let dragObj;
    loop(data, dragKey, (item, index, arr) => {
      arr.splice(index, 1);
      dragObj = item;
    });
    // 如果拖拽的是目录，那么需要遍历所有的子节点，改变\t个数
    if(dragObj.title.indexOf('- ') !== -1){
      // 放入的节点标题
      const title = info.node.props.dataRef.title;
      const addBool = !info.dropToGap || ((info.node.props.children || []).length > 0 && dropPosition === 1)
      upTitle(dragObj.children, addBool ? `\t${title}` : title);
    }

    // 是否要保存sidebar文件
    let bool = false;

    // dropToGap: true拖拽在节点中间  false拖拽到节点之上
    if (!info.dropToGap) {
      // 追加到尾部
      loop(data, dropKey, (item, index, arr) => {
        const {title} = item;
        if(title.indexOf('- ') === -1){
          return;
        }
        const childrenName = item.children.map(item=>item.title.trim());
        if(childrenName.includes(dragObj.title.trim())){
          message.error('不能与同级目录名称相同');
          return;
        }
        dragObj.title = `\t${title.substring(0, title.indexOf('- '))}${dragObj.title.trim()}`;
        item.children = item.children || [];
        item.children.push(dragObj);
        bool = true;
      });
    } else if (
      (info.node.props.children || []).length > 0 && // Has children
      dropPosition === 1 // On the bottom gap
    ) {
      // 拖拽到目录节点下
      loop(data, dropKey, item => {
        const childrenName = item.children.map(item=>item.title.trim())
        if(childrenName.includes(dragObj.title.trim())){
          message.error('不能与同级目录名称相同');
          return;
        }
        const {title} = item;
        dragObj.title = `\t${title.substring(0, title.indexOf('- '))}${dragObj.title.trim()}`;
        item.children = item.children || [];
        item.children.unshift(dragObj);
      });
      bool = true;
    } else {
      let ar;
      let i;
      loop(data, dropKey, (item, index, arr) => {
        ar = arr;
        i = index;
      });
      const childrenName = ar.map(item=>item.title.trim())
      if(childrenName.includes(dragObj.title.trim())){
        message.error('不能与同级目录名称相同');
        return;
      }
      dragObj.title = `${ar[i].title.substring(0, ar[i].title.indexOf('- '))}${dragObj.title.trim()}`;
      if (dropPosition === -1) {
        ar.splice(i, 0, dragObj);
      } else {
        ar.splice(i + 1, 0, dragObj);
      }
      bool = true;
    }
    bool && updateSidebar(treeToMd(data), 2);
    setMenuList(bool ? data : initMenuList);
  }

  // modal cancel
  function onCancel(){
    setVisible(false);
    setAddMenuError(undefined);
    setIsEditName(false);
    setMenuName(undefined);
  }

  // 展开收起全部节点
  function expandAll(){
    setIsExpendedAll(!isExpendedAll);
    if(isExpendedAll){
      setExpandedKeys([]);
      return;
    }
    const allKeys = [];
    findMenuKey(allKeys, menuList);
    setExpandedKeys(allKeys);
  }

  function findMenuKey(keys, list){
    list.map(item=>{
      if(item && !item.title.startsWith("[[")){
        keys.push(item.key);
      }
      if(item && item.children.length){
        findMenuKey(keys, item.children);
      }
    })
  }

  function changeSearchValue(value) {
    if(value){
      // 找到符合条件的子节点, 重新渲染页面
      let keysMap = findNodesToKeys(initMenuList, value);
      const newMenuList = [];
      let openedKeysMap = [];
      const oneNodeKeys = new Set();
      keysMap.map((item, index)=>{
        const {path, isFile, title} = item;
        // 把所有的一级目录key筛选出来
        oneNodeKeys.add(path[0]);
        openedKeysMap = openedKeysMap.concat(path);
        if(!index && isFile){
          setSelectedKey([path[path.length-1]]);
          const titleSplit = title.substring(2,title.length-2);
          changeitem({key: path[path.length-1], name: titleSplit})
        }
      })
      Array.from(oneNodeKeys).map(item=>loop(initMenuList, item,i=>{
        newMenuList.push(i);
      }))
      const openedKeys = Array.from(new Set(openedKeysMap));
      setExpandedKeys(openedKeys);
      setMenuList(newMenuList);
    }else{
      setMenuList(JSON.parse(JSON.stringify(initMenuList)));
    }
  }

  function findNodesToKeys(arr, value, path, nodes) {
    path = path || [];
    nodes = nodes || [];
    if (Array.isArray(arr)) {
      arr.forEach(function (obj, index) {
        if (obj && typeof obj === 'object') {
          const {children, key} = obj;
          const title = obj.title.trim();
          const isFile = title.startsWith('[[') && title.endsWith(']]');
          if (title.match(new RegExp(value, 'i'))) {
            nodes.push({path: path.concat([key]), isFile, title});
          } else {
            findNodesToKeys(children, value, path.concat([key]), nodes);
          }
        }
      });
    }
    return nodes;
  }

  return(
    <div className='wikiSidebar'>
      <Search
        allowClear
        placeholder="输入关键字搜索文件"
        className="wiki-search"
        onSearch={changeSearchValue}
      />

      {/* 目录是否全部展开 */}
      <div className='expendedAllAction mt5' onClick={expandAll}>{isExpendedAll ? '收起' : '展开'}所有节点</div>

      {/* wiki目录 */}
      {menuList && menuList.length ? <DirectoryTree onSelect={selectTree} draggable={permission} onDrop={onDrop} selectedKeys={selectedKey} expandedKeys={expandedKeys} onExpand={onExpand}>
        {renderTreeNodes(menuList)}
      </DirectoryTree> : ''}

      {/* 新增子目录弹窗 */}
      <Modal title={isEditName ? `编辑${isEditName === 1 ? '目录' : '页面'}` : "新增目录"} visible={Boolean(visible)} onCancel={onCancel} onOk={submit} className="wikiAddMenu myself-modal" width={450} centered>
        <div className='mb10'>{isEditName === 2 ? '页面' : '目录'}名称: </div>
        <Input placeholder={`请输入${isEditName === 2 ? '页面' : '目录'}名称`} value={menuName} onChange={(e)=>{setMenuName(e.target.value);setAddMenuError(undefined)}} maxLength={50}></Input>
        <div className='wikiAddMenuError mt5'>{addMenuError}</div>
      </Modal>
    </div>
  );
}