import { shallowRef, watch } from 'vue';
import { cloneDeep } from 'lodash-es';
import { CHECK_STRATEGY } from './const';
import { getChildrenByValues, getParentByValues } from './helper';

var useCheck = _ref => {
  let {
    allKeys,
    nodeList,
    currentCheckedKeys,
    updateCheckedKeys,
    props,
    emit
  } = _ref;
  function computeIndeterminate(node) {
    if (node.hasChildren) {
      if (node.isChecked.value) {
        node.isIndeterminate.value = false;
      } else {
        node.isIndeterminate.value = node.children.some(item => item.isChecked.value || item.isIndeterminate.value);
      }
    } else {
      node.isIndeterminate.value = false;
    }
  }
  function init() {
    if (props.checkable) {
      if (!props.cascade) {
        return currentCheckedKeys.value;
      }
      if (props.checkStrictly === CHECK_STRATEGY.ALL) {
        return currentCheckedKeys.value;
      }
      if (props.checkStrictly === CHECK_STRATEGY.PARENT) {
        return getChildrenByValues(nodeList, currentCheckedKeys.value);
      }
      if (props.checkStrictly === CHECK_STRATEGY.CHILD) {
        return getParentByValues(nodeList, currentCheckedKeys.value);
      }
      return currentCheckedKeys.value;
    }
    return [];
  }
  const _keys = shallowRef([]);
  let unwatch = false;
  let unwatchCurrent = false;
  watch([currentCheckedKeys, allKeys], () => {
    if (!props.checkable) {
      return;
    }
    if (unwatchCurrent) {
      unwatchCurrent = false;
      return;
    }
    _keys.value = init();
  }, {
    immediate: true,
    deep: true
  });
  watch(_keys, (newKeys, oldKeys) => {
    if (!props.checkable) {
      return;
    }
    if (unwatch) {
      unwatch = false;
      return;
    }
    // 重置历史节点选择状态
    if (Array.isArray(oldKeys)) {
      oldKeys.forEach(key => {
        const node = nodeList.get(key);
        node.isChecked.value = false;
      });
    }
    newKeys.forEach(key => {
      const node = nodeList.get(key);
      node.isChecked.value = true;
    });
    if (props.cascade) {
      allKeys.value.slice(0).reverse().forEach(key => {
        const node = nodeList.get(key);
        computeIndeterminate(node);
      });
    }
  }, {
    immediate: true
  });
  const computeCheckedKeys = (_values, node) => {
    const {
      hasChildren,
      childrenPath,
      indexPath,
      isChecked,
      value
    } = node;
    if (isChecked.value) {
      if (hasChildren) {
        childrenPath.forEach(key => {
          const childNode = nodeList.get(key);
          if (childNode.isChecked.value) {
            childNode.isChecked.value = false;
            const index = _values.indexOf(childNode.value);
            _values.splice(index, 1);
          }
          childNode.isIndeterminate.value = false;
        });
      }
      let len = indexPath.length - 1;
      for (len; len >= 0; len--) {
        const parentNode = nodeList.get(indexPath[len]);
        if (parentNode.isChecked.value) {
          parentNode.isChecked.value = false;
          const index = _values.indexOf(parentNode.value);
          _values.splice(index, 1);
        }
        computeIndeterminate(parentNode);
      }
    } else {
      if (hasChildren) {
        childrenPath.forEach(key => {
          const childNode = nodeList.get(key);
          if (!childNode.isChecked.value) {
            childNode.isChecked.value = true;
            _values.push(childNode.value);
          }
          childNode.isIndeterminate.value = false;
        });
      }

      // 选中
      _values.push(value);
      node.isChecked.value = true;
      computeIndeterminate(node);
      let len = indexPath.length - 2;
      for (len; len >= 0; len--) {
        const parentNode = nodeList.get(indexPath[len]);
        if (parentNode.children.every(childNode => childNode.isChecked.value)) {
          parentNode.isChecked.value = true;
          _values.push(parentNode.value);
        }
        computeIndeterminate(parentNode);
      }
    }
  };
  const checkNode = (val, event) => {
    const node = nodeList.get(val);
    unwatch = true;
    unwatchCurrent = true;
    const _values = cloneDeep(_keys.value);
    let values;
    if (!props.cascade) {
      // 非关联
      const index = _values.indexOf(val);
      if (node.isChecked.value) {
        _values.splice(index, 1);
      } else {
        _values.push(val);
      }
      node.isChecked.value = !node.isChecked.value;
      values = _values;
    } else {
      if (props.checkStrictly === CHECK_STRATEGY.ALL) {
        computeCheckedKeys(_values, node);
        values = _values;
      } else if (props.checkStrictly === CHECK_STRATEGY.PARENT) {
        computeCheckedKeys(_values, node);
        values = _values.filter(key => {
          const node = nodeList.get(key);
          return node.indexPath.filter(path => {
            const parenNode = nodeList.get(path);
            return parenNode.isChecked.value;
          }).length === 1;
        });
      } else if (props.checkStrictly === CHECK_STRATEGY.CHILD) {
        computeCheckedKeys(_values, node);
        values = _values.filter(key => {
          const node = nodeList.get(key);
          return node.isLeaf;
        });
      } else {
        computeCheckedKeys(_values, node);
        values = _values;
      }
    }
    _keys.value = _values;
    updateCheckedKeys(values);
    emit('check', {
      checkedKeys: values,
      event,
      node,
      checked: node.isChecked.value
    });
  };
  return {
    checkNode
  };
};

export { useCheck as default };
