/* eslint-disable no-unused-expressions */
import React, { useState, useEffect, forwardRef } from 'react';
import { Row, Col } from 'antd';
import styles from './index.less';
import CTreeNode from './CTreeNode';

const CustomTree = forwardRef(props => {
  const [treeData, setTreeData] = useState([]);
  const [childrenList, setChildrenList] = useState([]);
  const [initValue, setInitValue] = useState([]);

  // 初始化数据状态
  const initChildrenStatus = arr =>
    arr.map(item => {
      const obj = initValue.find(val => val.key === item.key) || {};
      item.checked = obj.checked || item.checked || false;
      item.indeterminate = obj.indeterminate || item.indeterminate || false;
      return item;
    });

  // 获取子列表
  const getChildrenList = list => {
    const arr = [];
    const findArr = childrens => {
      childrens.forEach(node => {
        if (node.children && node.children.length) {
          node.visibleChildren && arr.push(initChildrenStatus(node.children, node.checked));
          findArr(node.children);
        }
      });
    };
    findArr(list);
    return arr;
  };
  // 更改属性值
  const ChangeVal = (list, key, v, keyName) => {
    list.forEach(node => {
      if (node.key === key) {
        node[keyName] = v;
      } else if (node.children && node.children.length) {
        ChangeVal(node.children, key, v);
      }
    });
  };
  // 获取选中的值
  const getCheckValue = (list, isFrist) => {
    const arr = [];
    const getChildrenCheckValue = childrens => {
      childrens.forEach(item => {
        if (item.checked) {
          arr.push({ ...item, [props.valueKey]: item.key });
        } else if (item.children && !isFrist) {
          getChildrenCheckValue(item.children);
        }
      });
    };
    getChildrenCheckValue(list);
  };
  // 获取默认值是否选中
  const getIsChecked = (key, json) => {
    const checkfn = list => {
      list.forEach(item => {
        if (+item[props.valueKey || 'key'] === +key) {
          json.checked = !!item.checked;
          json.indeterminate = !item.checked;
          json.value = getCheckValue(item.children, 1);
        } else if (item.children) {
          checkfn(item.children);
        }
      });
    };
    props.value && props.value.length && checkfn(props.value, json);
  };
  // 格式化数据
  const filterData = (arr, parentChecked) => {
    const list = [];
    arr.forEach(item => {
      const json = {
        label: item.addrName,
        key: +item.addrId,
        level: item.addrLevel,
        value: [],
        checked: parentChecked || false,
        indeterminate: false,
        children: [],
        isLeaf: true,
        isLoading: false,
      };
      if (!parentChecked) {
        getIsChecked(item.addrId, json);
      }
      list.push(json);
    });
    return list;
  };

  // 更改子复选框状态
  const updateChildren = (list, isChecked) => {
    list.forEach(item => {
      item.indeterminate = false;
      item.checked = isChecked;
      if (item.children && item.children.length) {
        item.value = isChecked ? item.children.map(c => c.key) : [];
        updateChildren(item.children, isChecked);
      } else {
        item.value = [];
      }
    });
  };

  // 追加子树
  const appendTreeData = (list, key, children, isChecked) =>
    list.forEach(node => {
      if (node.key === key) {
        node.children = children.length ? children : [];
        isChecked && (node.value = children);
        updateChildren(node.children, isChecked);
      } else if (node.children && node.children.length) {
        appendTreeData(node.children, key, children, isChecked);
      }
    });

  // 更新子树显示隐藏状态
  const updateVisibleChildren = (list, visible) => {
    list.forEach(item => {
      item.visibleChildren = false;
      item.isLoading = false;
      if (item.children && item.children.length) {
        updateVisibleChildren(item.children, visible);
      }
    });
  };

  // 更新显示隐藏状态
  const updateVisible = (list, ckey, visible, pkey) => {
    let key = '';
    list.forEach(node => {
      node.isLoading = false;
      if (node.key === ckey) {
        node.visibleChildren = visible;
        key = pkey;
        node.isLeaf = node.children.length > 0;
        updateVisibleChildren(node.children, visible);
      } else if (node.children && node.children.length) {
        node.visibleChildren = false;
        if (updateVisible(node.children, ckey, visible, node.key) === node.key) {
          node.visibleChildren = true;
          key = pkey;
        } else {
          node.visibleChildren = false;
        }
      }
    });
    return key;
  };

  // 异步获取数据
  const getSyncLoadChildrens = async (arr, ckey, parentChecked) => {
    ChangeVal(arr, ckey, true, 'isLoading');
    setTreeData(arr);
    const res = await props.loadData({ key: ckey });
    if (res && res.length) {
      appendTreeData(arr, ckey, filterData(res, parentChecked), parentChecked);
    }
  };

  // 改变子树显示隐藏状态事件
  const onVisibleChildren = async (ckey, visible, children, parentChecked) => {
    const arr = [...treeData];
    if (children && !children.length && typeof props.loadData === 'function') {
      await getSyncLoadChildrens(arr, ckey, parentChecked);
    }
    updateVisible(arr, ckey, visible);
    setChildrenList(getChildrenList(arr));
    setTreeData(arr);
  };

  // 更改选中状态
  const changeChecked = (list, ckey, isChecked, pkey) => {
    let key = '';
    list.forEach(node => {
      if (node.key === ckey) {
        node.checked = isChecked;
        key = pkey;
        node.children && node.children.length && updateChildren(node.children, isChecked);
      } else if (node.children && node.children.length) {
        if (changeChecked(node.children, ckey, isChecked, node.key) === node.key) {
          if (!isChecked) {
            node.checked = false;
          } else {
            node.checked = node.children.every(item => item.checked);
          }
          key = pkey;
        }
      }
      if (node.checked) {
        node.indeterminate = false;
      } else if (node.children && node.children.length) {
        node.indeterminate = node.children.some(item => item.checked || item.indeterminate);
      }
    });
    return key;
  };

  // 获取选中的值
  const getCheckTreeValue = list => {
    const arr = [];
    const getChildrenCheckValue = (childrens, json, values = []) => {
      childrens.forEach(item => {
        if (item.checked || item.indeterminate) {
          const obj = { ...item };
          obj.children = [];
          json.children.push(obj);
          if (!item.checked) {
            const valueArr = values.find(val => val.key === item.key) || {};
            if (item.children && item.children.length) {
              getChildrenCheckValue(item.children, obj, valueArr.children);
            } else if (valueArr && valueArr.key) {
              obj.children = valueArr.children;
            }
          }
        }
      });
    };
    list.forEach(item => {
      if (item.checked || item.indeterminate) {
        const obj = { ...item };
        obj.children = [];
        if (!item.checked) {
          const valueArr = props.value.find(val => val.key === item.key) || {};
          if (item.children && item.children.length) {
            getChildrenCheckValue(item.children, obj, valueArr.children);
          } else if (valueArr && valueArr.key) {
            obj.children = valueArr.children;
          }
        }
        arr.push(obj);
      }
    });
    return arr;
  };

  // 切换选中状态事件
  const onChange = async (ckey, isChecked, level, children) => {
    const datas = [...treeData];
    if (isChecked && children && !children.length && typeof props.loadData === 'function') {
      await getSyncLoadChildrens(datas, ckey, isChecked);
    }
    changeChecked(datas, ckey, isChecked);
    const values = getCheckTreeValue(datas, isChecked);
    if (level === 1) {
      onVisibleChildren('', false);
    }
    props.onChange(values);
  };

  // 渲染子树
  const renderTreeNodes = data =>
    data &&
    data.map(item => (
      <CTreeNode
        label={item.label}
        onChange={onChange}
        onVisibleChildren={onVisibleChildren}
        key={item.key}
        treeData={item}
      />
    ));

  // 隐藏所有子树
  const handleMouseUp = e => {
    const isCur = e.path.some(
      item =>
        item.className &&
        typeof item.className === 'string' &&
        item.className.indexOf('CustomCTreeWrapper') > -1,
    );
    if (!isCur) {
      onVisibleChildren('', false);
    }
  };

  // 初始化数初始化
  const initTreeValue = (arr = [], values = [], parentChecked, level = 1) => {
    const getValues = (item, valueObj) => {
      if (item.checked && item.children && item.children.length) {
        return item.children.map(c => c.key);
      }
      return (valueObj.children || []).map(c => c.key);
    };

    arr.forEach(item => {
      const valueObj = values.find(val => val.key === item.key) || {};
      item.checked =
        (typeof parentChecked === 'boolean' && parentChecked) || valueObj.checked || false;
      item.indeterminate = valueObj.indeterminate || false;
      item.value = getValues(item, valueObj);
      item.isLeaf = typeof item.isLeaf === 'boolean' ? item.isLeaf : true;
      item.isLoading = false;
      item.visibleChildren = item.visibleChildren || false;
      item.level = level;
      if (item.children && item.children.length) {
        initTreeValue(item.children, valueObj.children, item.checked, level + 1);
      }
    });
  };
  const getInitValue = () => {
    const arr = [];
    const getDeepValue = list => {
      list.forEach(item => {
        const obj = { ...item };
        delete obj.children;
        arr.push(obj);
        if (item.children && item.children.length) {
          getDeepValue(item.children);
        }
      });
    };
    getDeepValue(props.value);
    return arr;
  };

  useEffect(() => {
    const datas = [...treeData];
    initTreeValue(datas, props.value);
    setTreeData(datas);
    const arr = getInitValue();
    setInitValue(arr);
  }, [props.value]);

  useEffect(() => {
    const datas = [...props.treeData];
    initTreeValue(datas, props.value);
    setTreeData(datas);
  }, [props.treeData]);

  // 委托 - 点击别的地方关闭子层
  useEffect(() => {
    window.addEventListener('mouseup', handleMouseUp);
    return () => {
      window.removeEventListener('mouseup', handleMouseUp);
    };
  }, [treeData]);

  return (
    <div className={styles['tree-box']} id="my-custom-tree-box">
      <Row justify="space-between">
        {(treeData.length &&
          treeData.map(item => (
            <Col span={7} key={`col${item.key}`}>
              <div className={`${styles['tree-box--wrapper']} CustomCTreeWrapper`}>
                <CTreeNode
                  label={item.label}
                  onChange={onChange}
                  onVisibleChildren={onVisibleChildren}
                  key={item.key}
                  treeData={item}
                ></CTreeNode>
                {(item.visibleChildren && childrenList && childrenList.length && (
                  <div className={styles['tree-children-box']} key="childrens">
                    {childrenList.map(arr => (
                      <div
                        className={styles['tree-children-wrapper']}
                        key={`children${arr[0].key}`}
                      >
                        {renderTreeNodes(arr) || ''}
                      </div>
                    ))}
                  </div>
                )) ||
                  ''}
              </div>
            </Col>
          ))) ||
          ''}
      </Row>
    </div>
  );
});
CustomTree.CTreeNode = CTreeNode;

export default CustomTree;
