import { defineComponent, inject, computed, createVNode, createTextVNode, mergeProps } from 'vue';
import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
import { isNil } from 'lodash-es';
import Tree from '../tree';
import Empty from '../empty';
import { SearchOutlined, CloseCircleOutlined } from '../icon';
import Input from '../input';
import VirtualList from '../virtual-list';
import { COMPONENT_NAME, TRANSFER_INJECT_KEY, COMPONENT_CLASS, COMPONENT_ONE_WAY_CLASS } from './const';
import { TransferCheckbox, calcCheckStatus } from './checkbox';
import { isTree, flattenTree, cls } from './utils';
import { useTreeFilter } from './useTreeFilter';
import { useCheckValueWithCheckbox } from './useCheckValueWithCheckbox';
import { useOptionsFilter } from './useOptionsFilter';

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 useData = _ref => {
  let {
    modelValue,
    rootProps,
    handleChange
  } = _ref;
  const options = computed(() => rootProps.options);
  const {
    checkboxStatus,
    handleCheckboxChange,
    handleCheck
  } = useCheckValueWithCheckbox({
    checkValue: modelValue,
    options,
    onCheckboxChange: () => {
      handleChange({
        nextValue: modelValue.value
      });
    }
  });
  return {
    treeCheckStatus: checkboxStatus,
    handleCheckStatusChange: handleCheckboxChange,
    handleTreeCheck: handleCheck
  };
};
const OneWayTransfer = defineComponent({
  name: COMPONENT_NAME,
  setup: () => {
    const {
      modelValue,
      rootProps,
      rootStyle,
      filter,
      renderLabel,
      handleChange,
      scrollContentHeight
    } = inject(TRANSFER_INJECT_KEY);
    const {
      handleTreeCheck,
      treeCheckStatus,
      handleCheckStatusChange
    } = useData({
      modelValue,
      rootProps,
      handleChange
    });
    const checkedOptions = computed(() => {
      const options = isTree(rootProps.options) ? flattenTree(rootProps.options) : rootProps.options;
      return options.filter(o => modelValue.value.includes(o.value));
    });
    const {
      treeRef,
      defaultFilterForTree,
      filterText: treeFilterText
    } = useTreeFilter({
      rootProps
    });

    // 右边 TargetList 需要的 filter
    const {
      displayOptions: displayCheckedOptions,
      filterText: checkedOptionsFilterText
    } = useOptionsFilter({
      options: checkedOptions,
      rootProps,
      filter: filter.value
    });
    const handleClear = () => {
      modelValue.value = [];
      treeCheckStatus.value = 'none';
      handleChange({
        nextValue: []
      });
    };
    const removeCheckedOption = optionValue => {
      const nextModelValue = [...modelValue.value];
      const index = nextModelValue.findIndex(v => v === optionValue);
      if (index === -1) {
        return;
      }
      nextModelValue.splice(index, 1);

      // 更新值
      modelValue.value = nextModelValue;
      treeCheckStatus.value = calcCheckStatus(nextModelValue.length, rootProps.options.length);
      handleChange({
        nextValue: nextModelValue
      });
    };
    const renderFilterInput = filterText => {
      if (!rootProps.filterable) {
        return undefined;
      }
      return createVNode(Input, {
        "modelValue": filterText.value,
        "onUpdate:modelValue": $event => filterText.value = $event,
        "class": cls('panel-filter'),
        "placeholder": '请输入'
      }, {
        suffix: () => createVNode(SearchOutlined, null, null)
      });
    };
    const renderSourcePanel = () => {
      var _ref2;
      // TODO: 在 options 为空的时候，应该也展示 Empty 组件。但是 Tree 组件需要绑定 ref，但是在 if-else 的 JSX 中绑定的 ref 会错乱

      const treeOptions = rootProps.options.map(option => _objectSpread(_objectSpread({}, option), {}, {
        label: () => renderLabel(option)
      }));
      const virtualScrollConfig = !isNil(scrollContentHeight.value) ? {
        virtualList: true,
        style: {
          height: `${scrollContentHeight.value}px`
        }
      } : {};
      const filterForTree = rootProps.filterable ? (_ref2 = rootProps.filter // TODO: is not assignable
      ) !== null && _ref2 !== void 0 ? _ref2 : defaultFilterForTree() : undefined;
      return createVNode("div", {
        "class": [cls('panel'), cls('source-panel')]
      }, [createVNode("div", {
        "class": [cls('panel-header')]
      }, [createVNode(TransferCheckbox, {
        "modelValue": treeCheckStatus.value,
        "onUpdate:modelValue": $event => treeCheckStatus.value = $event,
        "label": '全选',
        "disabled": rootProps.options.length === 0,
        "onChange": handleCheckStatusChange
      }, null), createVNode("span", {
        "class": cls('panel-count')
      }, [createTextVNode("\u5171 "), rootProps.options.length, createTextVNode(" \u9879")])]), renderFilterInput(treeFilterText), createVNode(Tree, mergeProps({
        'checkedKeys': modelValue.value,
        "onUpdate:checkedKeys": $event => modelValue.value = $event,
        "ref": treeRef,
        "data": treeOptions,
        "class": cls('panel-list'),
        "checkable": true,
        "selectable": false,
        "filterMethod": filterForTree,
        "onCheck": handleTreeCheck
      }, virtualScrollConfig), null)]);
    };
    const renderCheckedOption = option => {
      const labelContent = renderLabel(option);
      return createVNode("div", {
        "class": [cls('option'), cls('checked-option')]
      }, [createVNode("span", {
        "class": cls('checked-option-text')
      }, [labelContent]), createVNode(CloseCircleOutlined, {
        "class": cls('checked-option-remove-button'),
        "onClick": () => removeCheckedOption(option.value)
      }, null)]);
    };
    const renderTargetPanel = () => {
      const isEmpty = modelValue.value.length === 0;
      let content;
      if (isEmpty) {
        content = createVNode(Empty, {
          "class": cls('empty')
        }, null);
      } else if (!isNil(scrollContentHeight.value)) {
        content = createVNode(VirtualList, {
          "class": cls('panel-list'),
          "style": {
            height: `${scrollContentHeight.value}px`
          },
          "dataSources": displayCheckedOptions.value,
          "dataKey": option => option.value
        }, {
          default: _ref3 => {
            let {
              source: option
            } = _ref3;
            return renderCheckedOption(option);
          }
        });
      } else {
        content = createVNode("div", {
          "class": cls('panel-list')
        }, [displayCheckedOptions.value.map(renderCheckedOption)]);
      }
      return createVNode("div", {
        "class": [cls('panel'), cls('target-panel'), isEmpty && cls('empty-panel')]
      }, [createVNode("div", {
        "class": [cls('panel-header')]
      }, [createVNode("span", {
        "class": cls('panel-checked-count')
      }, [createTextVNode("\u5DF2\u9009 "), modelValue.value.length, createTextVNode(" \u9879")]), createVNode("span", {
        "class": cls('panel-clear-button'),
        "onClick": handleClear
      }, [createTextVNode("\u6E05\u9664")])]), renderFilterInput(checkedOptionsFilterText), content]);
    };
    return () => createVNode("div", {
      "class": [COMPONENT_CLASS, COMPONENT_ONE_WAY_CLASS],
      "style": rootStyle.value
    }, [renderSourcePanel(), renderTargetPanel()]);
  }
});

export { OneWayTransfer as default };
