/**
 * 1.引入组件 import RichText from '@wisdom-components/RichText'; 示例：<RichText
 *     content={this.state.content}
 *     personList={this.state.personList}
 *     placeholder={'placeholder属性值'}
 *     onChange={val => {
 *     this.setState({ content: val });
 *     }}
 *     onChangeFile={arr => {
 *     this.setState({ fileList: arr });
 *     }}
 *     fileList={this.state.fileList}
 *     projectId={19}
 *     ref={this.myRichText}
 *     />
 *
 * 2.传递方法 onChange 每次更改内容回调
 *
 * 3.传值接收 可选值 projectId 项目id，根据项目id获取项目参与人员，
 *     可选值 personList 人员列表 示例：[{userId:1,userName:'xxx'}]
 *     可选值 config 框架wangEditor的配置参数
 *
 * 4.注意事项 projectId和personList只用传一个，projectId优先级高于personList
 *     content内容如果不是初始有的，可调用setHtml设置内容
 *
 * 2022-03-21新增图片预览，附件上传功能 新增方法：onChangeFile 每次附件更改回调 若不传则不显示附件上传按钮
 *     fileList 附件列表 示例：[{name:'xxx.jpg',type:'image/jpg',size:8192,path:'xxxx'}]
 *     其中name和path是必传的，type为图片可以预览，其它类型文件直接下载
 *
 * 2022-04-29 修改@人员列表逻辑 personList 传任务相关人员列表（如 创建、负责、跟进人），同时传入projectId,personList
 * 下拉列表默认显示为任务相关人员，加项目人员（做了去重，任务相关人员在最上面）
 *
 * @搜索时，搜索全部人员
 */

import { Image, message, Spin } from 'antd';
import classNames from 'classnames';
import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
import request from 'umi-request';
import FileListItem from './fileListItem';
import styles from './index.less';
import WangEditor from './wangEditor.js';

const baseUrl = '';
const API = {
  POST_UPLOADERFILES: `${baseUrl}/PandaWorkFlow/WorkFlow/AccountManage/UploaderFiles`,
  GET_DOWNLOADFILES: `${baseUrl}/PandaWorkFlow/WorkFlow/AccountManage/DownloadFiles`,
  GET_GETALLPERSONNELS: `${baseUrl}/PandaWorkFlow/WorkFlow/WorkFlow/GetUserSelector`, // 获取人员
  GET_WORKHOURUSERLIST: `${baseUrl}/PandaInformatization/PandaWork/ProjectManage/GetWorkHourUserList`, //根据项目id获取项目参与人员
};
let editor = null;
let range;
const selection = window.getSelection();
let startOffset;
let tempList = [];
let allPeople = []; // 全部人员
let selectPersonIndex;
let selectPerson = [];

const RichText = forwardRef((props, ref) => {
  const {
    getUserType = true, // 是否获取所有人(@搜索用)
    showAt = true, // 是否@ 人员
    pasteImg = true, // 粘贴图片上传
  } = props;
  const [loading, setLoading] = useState(false);
  const [zIndex, setZIndex] = useState(500);
  const [selectIndex, setSelectIndex] = useState(null);
  const [selectList, setSelectList] = useState([]);
  const [selectSearchList, setSelectSearchList] = useState([]);
  const [fileList, setFileList] = useState([]);
  const [imgVisible, setImgVisible] = useState(false);
  const [imgPreviewSrc, setImgPreviewSrc] = useState('');
  const richTextRef = useRef();
  const selectBoxRef = useRef();
  const fileInputRef = useRef();
  const getData = () => {
    request(API.GET_WORKHOURUSERLIST, {
      method: 'get',
      params: { projectId: props.projectId },
    }).then((res) => {
      setSelectList(res.data || []);
    });
  };
  // 获取全部人员信息
  const getAllPeople = async () => {
    request(API.GET_GETALLPERSONNELS, {
      method: 'get',
      params: {},
    }).then((res) => {
      let list = res?.data?.dropdownList || [];
      allPeople = list.map((l) => {
        l.name = l.userName;
        l.id = l.userID;
        l.port = '';
        return l;
      });
    });
  };
  // 图片上传
  const uploadImg = (file) => {
    const formData = new FormData();
    formData.append('file', file);
    setLoading(true);
    request(API.POST_UPLOADERFILES, {
      method: 'POST',
      data: formData,
    })
      .then((res) => {
        if (!res.data) {
          setLoading(false);
          return;
        }
        const img = res.data.replace(/[\\ \/=]/g, '/');
        const imgHtml = `
                    <img contenteditable="false" style="display: block;" width="50%" src="${API.GET_DOWNLOADFILES}?filePath=${img}" >
                `;
        editor.cmd.do('insertHTML', imgHtml);
        setLoading(false);
      })
      .catch((err) => {
        setLoading(false);
      });
  };
  const init = () => {
    const { BtnMenu } = WangEditor;
    editor = new WangEditor('#RichTextToolbar', '#RichTextContainer');
    // 自定义菜单
    const menuKey = 'fileMenuKey';
    if (props.onChangeFile) {
      class InsertABCMenu extends BtnMenu {
        constructor(editor) {
          const $elem = WangEditor.$(
            `<div class="w-e-menu">
                            <i class="w-e-icon-link">
                            </i>
                        </div>`,
          );
          super($elem, editor);
        }

        // 菜单点击事件
        clickHandler() {
          // 触发选择文件
          fileInputRef.current.click();
        }

        // 菜单激活状态
        tryChangeActive() {
          // this.active(); // 菜单激活
        }
      }
      editor.menus.extend(menuKey, InsertABCMenu);
    }
    editor.config = Object.assign(
      {},
      editor.config,
      {
        placeholder: props.placeholder ?? '',
        focus: false,
        pasteFilterStyle: true, // 忽略粘贴样式
        pasteIgnoreImg: true, // 忽略粘贴的图片
        styleWithCSS: false,
        zIndex: 500,
        menus: [
          'bold',
          'fontSize',
          'italic',
          'underline',
          'strikeThrough',
          'foreColor',
          'backColor',
          'list',
          'justify',
          'table',
          menuKey,
          'undo',
          'redo',
          'image',
        ],
      },
      props.config || {},
    );

    setZIndex(Number(editor.config.zIndex));
    // 内容变更
    editor.config.onchange = (newHtml, e) => {
      props.onChange(newHtml);
    };
    // 粘贴前置处理
    editor.config.pasteTextHandle = (pasteStr) => pasteStr;
    editor.config.onblur = (newHtml) => {
      selectBoxRef.current.style.display = 'none';
    };
    // 点击事件
    editor.txt.eventHooks.clickEvents.push((e) => {
      // 图片预览
      // 已弃用
      if (e.target.getAttribute('type') === 'preview') {
        const imgSrc = e.target?.parentNode?.parentNode
          ?.getElementsByTagName('img')?.[0]
          ?.getAttribute('src');
        setImgPreviewSrc(imgSrc);
        setImgVisible(true);
      }
      // 关闭选人的下拉框
      selectBoxRef.current.style.display = 'none';
    });

    editor.txt.eventHooks.onPreviewEvents.push((link) => {
      // 图片预览
      if (link) {
        setImgPreviewSrc(link);
        setImgVisible(true);
      }
    });

    editor.txt.eventHooks.imgClickEvents.push((e) => {});
    if (pasteImg) {
      // 粘贴图片上传
      editor.txt.eventHooks.pasteEvents.push((e) => {
        const file = e?.clipboardData?.items[0]?.getAsFile() || null;
        if (!file) return;
        uploadImg(file);
      });
    }

    editor.create();
    editor.txt.html(props.content || '');
    richTextRef.current.onkeydown = keyDownEvent;
    if (showAt) {
      richTextRef.current.addEventListener('input', (e) => {
        if (range) {
          // 判断节点是否在选区及光标是否在@后面
          const type = selection.containsNode(
            selection.getRangeAt(0).commonAncestorContainer,
            false,
          );
          if (!type || startOffset > selection.focusOffset) {
            closeList();
            return;
          }
          range.setEnd(selection.getRangeAt(0).commonAncestorContainer, selection.focusOffset);
          const str = range.toString() || '';
          moveListBox();
          handleChange(str, tempList);
        }
        if (e.data !== '@') return;
        if (range) {
          closeList();
        }
        range = document.createRange();
        startOffset = selection.focusOffset;
        range.setStart(selection.getRangeAt(0).commonAncestorContainer, selection.focusOffset);
        selection.addRange(range);
        moveListBox();
        // 清空搜索
        handleChange('', tempList);
      });
    }
  };
  // 跟据光标位置移动下拉框
  const moveListBox = () => {
    // 获取光标位置
    const cursor = window?.getSelection()?.getRangeAt(0)?.getBoundingClientRect() || null;
    const containerRect = document.querySelector('#RichText').getBoundingClientRect();
    selectBoxRef.current.style.display = 'block';
    selectBoxRef.current.style.left = `${parseInt(cursor.x - containerRect.x, 10) + 5}px`;
    selectBoxRef.current.style.top = `${parseInt(cursor.y - containerRect.y, 10) + 25}px`;
  };
  // 键盘事件
  const keyDownEvent = (evet) => {
    // 上下方向键
    if (evet.key === 'ArrowDown' || evet.key === 'ArrowUp') {
      if (selectBoxRef.current?.style?.display === 'block') {
        evet.preventDefault();
        const max = selectBoxRef.current.querySelectorAll('.selectItem')?.length || 1000;
        let val = selectPersonIndex;
        if (evet.key === 'ArrowDown') {
          if (!val && val != 0) {
            val = 0;
          } else {
            val += 1;
          }
        }
        if (evet.key === 'ArrowUp') val -= 1;
        if (isNaN(val) || !val || val < 0) val = 0;
        if (val > max - 1) val = max - 1;
        selectPersonIndex = val;
        setSelectIndex(selectPersonIndex);
      }
    }
    if (evet.key === 'Enter') {
      // 解决无法回车换行的bug
      if (selectBoxRef.current.style.display === 'block') {
        evet.preventDefault();
        if (selectPerson[selectPersonIndex]) {
          onSelect(selectPerson[selectPersonIndex]);
        }
        return false;
      }
    }
  };

  useEffect(() => {
    richTextRef.current && richTextRef.current.removeEventListener('input', (e) => {});
    init();
    getUserType && getAllPeople();
    return () => {
      richTextRef.current && richTextRef.current.removeEventListener('input', (e) => {});
      editor && editor.destroy();
      editor = null;
    };
  }, []);
  useEffect(() => {
    selectPersonIndex = null;
    setSelectIndex(null);
    selectPerson = selectSearchList || [];
  }, [selectSearchList]);
  useEffect(() => {
    if (props.projectId) getData();
  }, [props.projectId]);
  useEffect(() => {
    const keys = [];
    const arr = [];
    if (props.personList) {
      props.personList.forEach((i) => {
        i.userId = Number(i.userId);
        if (!keys.includes(i.userId)) {
          keys.push(i.userId);
          arr.push(i);
        }
      });
    }
    if (selectList) {
      selectList.forEach((i) => {
        i.userId = Number(i.userId);
        if (!keys.includes(i.userId)) {
          arr.push(i);
          keys.push(i.userId);
        }
      });
    }

    tempList = arr;
    setSelectSearchList(arr);
  }, [selectList, props.personList]);

  useEffect(() => {
    setFileList(props.fileList);
  }, [props.fileList]);
  const getHtml = (val) => editor.txt.html();
  // 获取文本，不含标签
  const getText = (val) => editor.txt.text();
  // 清除
  const onClear = () => {
    editor.txt.clear();
  };
  // 设置内容
  const setHtml = (val) => {
    editor.txt.html(val || '');
  };
  // 关闭人员下拉选框
  const closeList = () => {
    selectPersonIndex = null;
    setSelectIndex(null);
    selectBoxRef.current.style.display = 'none';
    if (range) {
      selection.removeRange(range);
      range = null;
    }
  };
  // @某人
  const onSelect = (item) => {
    if (range) {
      range.deleteContents();
      // 删除前一个@符号
      editor.cmd.do('delete');
      const _html = `<span><span data-userId="${item.userId}" data-type="person" >@${item.userName}</span><span>&nbsp;</span></span>`;
      editor.cmd.do('insertElem', _html);
      closeList();
      selection.collapseToEnd();
    }
  };
  let timer = null;
  const filterList = (val, list) => {
    if (!val) {
      if (list.length === 0) {
        selectBoxRef.current.style.display = 'none';
      }
      setSelectSearchList(list);
    } else {
      const arr = getArrayByName(val, allPeople);
      if (arr.length === 0) {
        selectBoxRef.current.style.display = 'none';
      }
      setSelectSearchList(arr);
    }
  };
  const handleChange = (val, list) => {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      timer = null;
      filterList(val, list);
    }, 200);
    // filterList(val, list);
  };
  /** 根据字符串模糊搜索返回符合条件的数据 name 搜索字符串 array 检索json数组 */
  const getArrayByName = (name, array) => {
    const result = [];
    array.forEach((i) => {
      if (i.name.indexOf(name) != -1) result.push({ userName: i.name, userId: i.id, port: i.port });
    });
    return result;
  };
  const addFile = (e) => {
    if (e.target) {
      let file = e.target.files[0];
      const pattern =
        /[`~!@#$^\-&*()+=|{}':;',\\\[\]\<>\/?~！@#￥……&*（）——|{}【】'；：""'。，、？\s]/g;
      let name = file.name.replace(pattern, '');
      const renameFile = new File([file], name);
      const formData = new FormData();
      formData.append('file', renameFile);
      setLoading(true);
      request(API.POST_UPLOADERFILES, {
        method: 'POST',
        data: formData,
      })
        .then((res) => {
          if (res.data) {
            const arr = [...fileList];
            const url = res.data.replace(/[\\ \/=]/g, '/');
            arr.unshift({
              name: name,
              type: file.type ? file.type.toLowerCase() : '',
              size: file.size,
              path: `${API.GET_DOWNLOADFILES}?filePath=${url}`,
            });
            // setFileList(arr);
            props.onChangeFile(arr);
            setLoading(false);
          } else {
            res && message.error(res.msg);
            setLoading(false);
          }
        })
        .catch((err) => {
          setLoading(false);
        });
    }
  };
  const onDelFile = (item) => {
    const arr = [];
    fileList.forEach((i) => {
      if (i.path !== item.path) {
        arr.push(i);
      }
    });
    // setFileList(arr);
    props.onChangeFile(arr);
  };
  useImperativeHandle(ref, () => ({
    setHtml,
    onClear,
    getHtml,
    getText,
  }));
  return (
    <div className={styles.RichText} id="RichText">
      {loading ? (
        <div className={styles.loadingWrap} style={{ zIndex: zIndex + 20 }}>
          <Spin spinning={loading} />
        </div>
      ) : null}
      <div id="RichTextToolbar" className={styles.RichTextToolbar} />
      <div ref={richTextRef} id="RichTextContainer" className={styles.RichTextContainer} />
      <div className={styles.RichTextFileList}>
        <FileListItem
          list={fileList}
          onDel={(val) => {
            onDelFile(val);
          }}
          type="edit"
          onPreview={(val) => {
            if (!val) return;
            setImgPreviewSrc(val.path);
            setImgVisible(true);
          }}
        />
      </div>
      <div
        ref={selectBoxRef}
        className={styles.selectBox}
        style={{ maxWidth: '300px', minWidth: '150px', zIndex: zIndex + 10 }}
      >
        {selectSearchList.length ? (
          <div className={styles.selectList}>
            {selectSearchList.map((item, index) => (
              <div
                key={item.userId}
                onClick={() => {
                  onSelect(item);
                }}
                className={classNames(
                  'selectItem',
                  styles.selectItem,
                  selectIndex === index ? styles.selectActiveItem : '',
                )}
              >
                {item.userName}
              </div>
            ))}
          </div>
        ) : null}
      </div>
      <input
        style={{ display: 'none' }}
        type="file"
        ref={fileInputRef}
        onChange={(e) => {
          addFile(e);
        }}
        name="file"
      />
      <Image
        width={200}
        style={{ display: 'none' }}
        src={imgPreviewSrc}
        preview={{
          visible: imgVisible,
          src: imgPreviewSrc,
          onVisibleChange: (value) => {
            setImgVisible(value);
            if (!value) setImgPreviewSrc('');
          },
        }}
      />
    </div>
  );
});
export default RichText;
