import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
import { defineComponent, computed, ref, watch, unref, resolveComponent, openBlock, createElementBlock, normalizeClass, createVNode, withCtx, normalizeStyle, withDirectives, withModifiers, vShow } from 'vue';
import { isArray, debounce } from 'lodash-es';
import getPrefixCls from '../_util/getPrefixCls';
import { useTheme } from '../_theme/useTheme';
import { useArrayModel, useNormalModel } from '../_util/use/useModel';
import { UPDATE_MODEL_EVENT, CHANGE_EVENT } from '../_util/constants';
import useFormAdaptor from '../_util/use/useFormAdaptor';
import Popper from '../popper';
import SelectTrigger from '../select-trigger';
import Cascader from '../cascader/cascader';
import { selectProps } from '../select/props';
import { cascaderProps } from '../cascader/props';
import { getCascadeChildrenByKeys, getCascadeParentByKeys, handleParent, handleChildren } from '../cascader/helper';
import { useLocale } from '../config-provider/useLocale';
import { CHECK_STRATEGY } from '../cascader/const';
import OptionList from '../select/optionList';
import { prefixCls as prefixCls$1 } from '../select/const';
import { getKeysByCurrentValue, getExpandedKeysBySelectedKeys, getNotMatchedPathByKey, getCurrentValueByKeys } from './helper';
import { SELECT_CASCADER_NAME, LABEL_SEPARATOR } from './const';

function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
const prefixCls = getPrefixCls('select-cascader');
const selectCascaderProps = _objectSpread(_objectSpread(_objectSpread({}, selectProps), cascaderProps), {}, {
  modelValue: {
    type: [String, Number, Array]
  }
});
var script = defineComponent({
  name: SELECT_CASCADER_NAME,
  components: {
    Popper,
    SelectTrigger,
    Cascader,
    OptionList
  },
  props: selectCascaderProps,
  emits: [UPDATE_MODEL_EVENT, CHANGE_EVENT, 'update:expandedKeys', 'removeTag', 'visibleChange', 'focus', 'blur', 'clear'],
  setup(props, _ref) {
    let {
      emit,
      attrs
    } = _ref;
    useTheme();
    const {
      validate,
      isError,
      isFormDisabled
    } = useFormAdaptor({
      valueType: computed(() => props.multiple ? 'array' : 'string')
    });
    const isOpened = ref(false);

    // 与 props 中 modelValue 类型保持一致
    const [currentValue, updateCurrentValue] = props.multiple ? useArrayModel(props, emit) : useNormalModel(props, emit);
    const innerDisabled = computed(() => props.disabled || isFormDisabled.value);
    const cascaderRef = ref();
    const triggerDomRef = ref();
    const triggerWidth = ref(0);
    const innerFilterable = computed(() => {
      if (props.filterable && props.remote) {
        console.warn(`[${SELECT_CASCADER_NAME}]: remote 被设定时, filterable 不生效`);
      }
      return props.filterable && !props.remote && !innerDisabled.value;
    });
    const filterText = ref('');
    const filteredOptions = ref([]);
    const {
      t
    } = useLocale();
    const inputPlaceholder = computed(() => props.placeholder || t('select.placeholder'));
    const listEmptyText = computed(() => props.emptyText || t('select.emptyText'));
    const filterEmptyText = computed(() => t('select.filterEmptyText'));
    watch(isOpened, () => {
      emit('visibleChange', unref(isOpened));

      // trigger 在 mounted 之后可能会改变
      if (isOpened.value && triggerDomRef.value) {
        triggerWidth.value = triggerDomRef.value.$el.offsetWidth;
      }
    });
    const handleChange = () => {
      emit(CHANGE_EVENT, currentValue.value);
      validate(CHANGE_EVENT);
    };
    const nodeList = ref({});
    const onChangeNodeList = data => {
      nodeList.value = data;
    };
    // 为避免过滤项之间选中操作相互干扰，这里仅过滤叶子节点
    const filterNodeList = computed(() => {
      const list = [];
      if (innerFilterable.value) {
        Object.keys(nodeList.value).forEach(key => {
          if (!nodeList.value[key].hasChildren) {
            list.push(nodeList.value[key]);
          }
        });
      }
      return list;
    });
    const cascaderSelectable = computed(() => !props.multiple);
    const cascaderCheckable = computed(() => props.multiple);
    const selectedKeys = computed(() => {
      if (!props.multiple) {
        return getKeysByCurrentValue(currentValue.value, props);
      }
      return [];
    });
    const expandedKeys = computed({
      get: () => {
        if (!props.multiple) {
          return getExpandedKeysBySelectedKeys(nodeList.value, selectedKeys.value);
        }
        return [];
      },
      set: nextValue => {
        emit('update:expandedKeys', nextValue);
      }
    });
    const checkedKeys = computed(() => {
      if (props.multiple) {
        const keys = getKeysByCurrentValue(currentValue.value, props);
        if (!props.cascade) {
          return keys;
        }
        if (props.checkStrictly === CHECK_STRATEGY.ALL) {
          return keys;
        }
        if (props.checkStrictly === CHECK_STRATEGY.PARENT) {
          return getCascadeChildrenByKeys(nodeList.value, keys);
        }
        if (props.checkStrictly === CHECK_STRATEGY.CHILD) {
          return getCascadeParentByKeys(nodeList.value, keys);
        }
      }
      return [];
    });
    const initLoadKeys = computed(() => {
      let keys = [];
      if (!(props.remote && props.loadData)) {
        return keys;
      }
      if (!props.emitPath) {
        return keys;
      }
      if (!isArray(currentValue.value)) {
        return keys;
      }
      currentValue.value.forEach(value => keys = keys.concat(value));
      keys = Array.from(new Set(keys)); // 去重处理
      return keys;
    });
    watch(() => props.checkStrictly, () => {
      if (props.multiple && props.cascade) {
        updateCurrentValue([]);
        handleChange();
      }
    });
    watch([() => props.emitPath, () => props.cascade], () => {
      const value = props.multiple || props.emitPath ? [] : null;
      updateCurrentValue(value);
      handleChange();
    });
    const handleClear = () => {
      const value = props.multiple || props.emitPath ? [] : null;
      if (props.multiple ? checkedKeys.value.length : selectedKeys.value.length) {
        updateCurrentValue(value);
        handleChange();
      }
      filterText.value = '';
      emit('clear');
    };
    const handleSelect = data => {
      if (innerDisabled.value) {
        return;
      }
      if (!props.multiple) {
        isOpened.value = false;
      }
      updateCurrentValue(getCurrentValueByKeys(nodeList.value, data.selectedKeys, props));
      handleChange();
    };
    const handleCheck = data => {
      if (innerDisabled.value) {
        return;
      }
      if (!props.multiple) {
        isOpened.value = false;
      }
      updateCurrentValue(getCurrentValueByKeys(nodeList.value, data.checkedKeys, props));
      handleChange();
    };
    const handleRemove = value => {
      if (!props.multiple) {
        return;
      }
      const values = getKeysByCurrentValue(currentValue.value, props);
      const findIndex = values.indexOf(value);
      if (findIndex !== -1) {
        emit('removeTag', value);

        // 兼容关联场景
        if (!props.cascade) {
          values.splice(findIndex, 1);
        } else {
          const {
            isLeaf,
            children,
            indexPath
          } = nodeList.value[value];
          values.splice(findIndex, 1);
          handleParent(values, indexPath, false, nodeList.value);
          if (!isLeaf) {
            handleChildren(values, children, false);
          }
        }
        updateCurrentValue(getCurrentValueByKeys(nodeList.value, values, props));
        handleChange();
      }
    };
    const selectedOptions = computed(() => {
      const values = getKeysByCurrentValue(currentValue.value, props);

      // 兼容异步加载，未匹配到节点的情况
      return values.filter(Boolean).map(curValue => {
        const {
          value,
          label,
          path
        } = nodeList.value[curValue] || {
          value: curValue,
          label: curValue,
          path: getNotMatchedPathByKey(currentValue.value, props, curValue)
        };
        const formatLabel = props.showPath ? path.map(item => `${item.label}`).join(LABEL_SEPARATOR) : label;
        return {
          value,
          label: formatLabel,
          path
        };
      });
    });
    const focus = e => {
      emit('focus', e);
      validate('focus');
    };
    const blur = e => {
      if (isOpened.value) {
        isOpened.value = false;
      }
      filterText.value = '';
      emit('blur', e);
      validate('blur');
    };
    const handleFilterTextChange = val => {
      filterText.value = val;
    };
    watch(filterText, debounce(() => {
      const currentNodeList = [];
      if (innerFilterable.value && filterText.value) {
        filterNodeList.value.forEach(node => {
          let isFilter = false;
          const labelList = node.path.map(item => item.label);
          if (props.filter) {
            isFilter = props.filter(filterText.value, node);
          } else {
            isFilter = labelList.some(label => String(label).includes(filterText.value));
          }
          if (isFilter) {
            currentNodeList.push({
              value: node.value,
              label: labelList.join(LABEL_SEPARATOR),
              disabled: node.disabled
            });
          }
        });
      }
      filteredOptions.value = currentNodeList;
    }, 300));
    const filterIsSelect = value => {
      const optVal = unref(value);
      if (cascaderSelectable.value) {
        return selectedKeys.value.includes(optVal);
      }
      if (cascaderCheckable.value) {
        return checkedKeys.value.includes(optVal);
      }
    };
    const filterDropdownStyle = computed(() => {
      const style = {};
      if (triggerWidth.value) {
        style['min-width'] = `${triggerWidth.value}px`;
      }
      return style;
    });
    const handleFilterSelect = value => {
      if (cascaderSelectable.value) {
        var _cascaderRef$value;
        (_cascaderRef$value = cascaderRef.value) === null || _cascaderRef$value === void 0 || _cascaderRef$value.selectNode(value);
        filterText.value = '';
      }
      if (cascaderCheckable.value) {
        var _cascaderRef$value2;
        (_cascaderRef$value2 = cascaderRef.value) === null || _cascaderRef$value2 === void 0 || _cascaderRef$value2.checkNode(value);
      }
    };
    return {
      triggerDomRef,
      cascaderRef,
      prefixCls,
      selectPrefixCls: prefixCls$1,
      isOpened,
      currentValue,
      handleRemove,
      handleClear,
      selectedOptions,
      focus,
      blur,
      handleFilterTextChange,
      cascaderSelectable,
      selectedKeys,
      expandedKeys,
      cascaderCheckable,
      handleSelect,
      handleCheck,
      checkedKeys,
      onChangeNodeList,
      inputPlaceholder,
      isError,
      initLoadKeys,
      attrs,
      innerDisabled,
      innerFilterable,
      listEmptyText,
      filterEmptyText,
      filterText,
      filteredOptions,
      filterIsSelect,
      filterDropdownStyle,
      handleFilterSelect
    };
  }
});

function render(_ctx, _cache, $props, $setup, $data, $options) {
  const _component_SelectTrigger = resolveComponent("SelectTrigger");
  const _component_Cascader = resolveComponent("Cascader");
  const _component_OptionList = resolveComponent("OptionList");
  const _component_Popper = resolveComponent("Popper");
  return openBlock(), createElementBlock("div", {
    class: normalizeClass(_ctx.prefixCls)
  }, [createVNode(_component_Popper, {
    modelValue: _ctx.isOpened,
    "onUpdate:modelValue": _cache[3] || (_cache[3] = $event => _ctx.isOpened = $event),
    trigger: "click",
    placement: "bottom-start",
    popperClass: `${_ctx.prefixCls}-popper`,
    appendToContainer: _ctx.appendToContainer,
    getContainer: _ctx.getContainer,
    offset: 4,
    hideAfter: 0,
    disabled: _ctx.innerDisabled,
    lazy: false
  }, {
    trigger: withCtx(() => [createVNode(_component_SelectTrigger, {
      ref: "triggerDomRef",
      selectedOptions: _ctx.selectedOptions,
      disabled: _ctx.innerDisabled,
      clearable: _ctx.clearable,
      isOpened: _ctx.isOpened,
      multiple: _ctx.multiple,
      placeholder: _ctx.inputPlaceholder,
      filterable: _ctx.innerFilterable,
      collapseTags: _ctx.collapseTags,
      collapseTagsLimit: _ctx.collapseTagsLimit,
      tagBordered: _ctx.tagBordered,
      class: normalizeClass([{
        'is-error': _ctx.isError
      }, _ctx.attrs.class]),
      style: normalizeStyle(_ctx.attrs.style),
      renderTag: _ctx.$slots.tag,
      onRemove: _ctx.handleRemove,
      onClear: _ctx.handleClear,
      onFocus: _ctx.focus,
      onBlur: _ctx.blur,
      onInput: _ctx.handleFilterTextChange
    }, null, 8 /* PROPS */, ["selectedOptions", "disabled", "clearable", "isOpened", "multiple", "placeholder", "filterable", "collapseTags", "collapseTagsLimit", "tagBordered", "class", "style", "renderTag", "onRemove", "onClear", "onFocus", "onBlur", "onInput"])]),
    default: withCtx(() => [withDirectives(createVNode(_component_Cascader, {
      ref: "cascaderRef",
      expandedKeys: _ctx.expandedKeys,
      "onUpdate:expandedKeys": _cache[0] || (_cache[0] = $event => _ctx.expandedKeys = $event),
      selectedKeys: _ctx.selectedKeys,
      checkedKeys: _ctx.checkedKeys,
      initLoadKeys: _ctx.initLoadKeys,
      data: _ctx.data,
      emptyText: _ctx.listEmptyText,
      selectable: _ctx.cascaderSelectable,
      checkable: _ctx.cascaderCheckable,
      checkStrictly: _ctx.checkStrictly,
      cascade: _ctx.cascade,
      multiple: _ctx.multiple,
      childrenField: _ctx.childrenField,
      valueField: _ctx.valueField,
      labelField: _ctx.labelField,
      remote: _ctx.remote,
      loadData: _ctx.loadData,
      expandTrigger: _ctx.expandTrigger,
      isOpened: _ctx.isOpened,
      "onUpdate:nodeList": _ctx.onChangeNodeList,
      onSelect: _ctx.handleSelect,
      onCheck: _ctx.handleCheck,
      onMousedown: _cache[1] || (_cache[1] = withModifiers(() => {}, ["prevent"]))
    }, null, 8 /* PROPS */, ["expandedKeys", "selectedKeys", "checkedKeys", "initLoadKeys", "data", "emptyText", "selectable", "checkable", "checkStrictly", "cascade", "multiple", "childrenField", "valueField", "labelField", "remote", "loadData", "expandTrigger", "isOpened", "onUpdate:nodeList", "onSelect", "onCheck"]), [[vShow, !_ctx.filterText]]), withDirectives(createVNode(_component_OptionList, {
      options: _ctx.filteredOptions,
      prefixCls: _ctx.selectPrefixCls,
      containerStyle: _ctx.filterDropdownStyle,
      isSelect: _ctx.filterIsSelect,
      onSelect: _ctx.handleFilterSelect,
      emptyText: _ctx.filterEmptyText,
      filterText: _ctx.filterText,
      filterTextHighlight: _ctx.filterTextHighlight,
      onMousedown: _cache[2] || (_cache[2] = withModifiers(() => {}, ["prevent"]))
    }, null, 8 /* PROPS */, ["options", "prefixCls", "containerStyle", "isSelect", "onSelect", "emptyText", "filterText", "filterTextHighlight"]), [[vShow, _ctx.filterText]])]),
    _: 1 /* STABLE */
  }, 8 /* PROPS */, ["modelValue", "popperClass", "appendToContainer", "getContainer", "disabled"])], 2 /* CLASS */);
}

script.render = render;
script.__file = "components/select-cascader/selectCascader.vue";

export { script as default, selectCascaderProps };
