<script>
import ElCheckbox from 'bi-element/packages/checkbox';
import ElRadio from 'bi-element/packages/radio';
import { isEqual } from 'bi-element/src/utils/util';

const stopPropagation = (e) => e.stopPropagation();

export default {
  inject: ['panel'],

  components: {
    ElCheckbox,
    ElRadio
  },

  props: {
    node: {
      required: true
    },
    nodeId: String
  },

  computed: {
    config() {
      return this.panel.config;
    },
    isLeaf() {
      return this.node.isLeaf;
    },
    isDisabled() {
      return this.node.isDisabled;
    },
    checkedValue() {
      return this.panel.checkedValue;
    },
    isChecked() {
      return this.node.isSameNode(this.checkedValue);
    },
    inActivePath() {
      return this.isInPath(this.panel.activePath);
    },
    inCheckedPath() {
      if (!this.config.checkStrictly) return false;

      return this.panel.checkedNodePaths.some((checkedPath) =>
        this.isInPath(checkedPath)
      );
    },
    value() {
      return this.node.getValueByOption();
    }
  },

  methods: {
    handleExpand() {
      const { panel, node, isDisabled, config } = this;
      const { multiple, checkStrictly } = config;

      if ((!checkStrictly && isDisabled) || node.loading) return;

      if (config.lazy && !node.loaded) {
        panel.lazyLoad(node, () => {
          // do not use cached leaf value here, invoke this.isLeaf to get new value.
          const { isLeaf } = this;

          if (!isLeaf) this.handleExpand();
          if (multiple) {
            // if leaf sync checked state, else clear checked state
            const checked = isLeaf ? node.checked : false;
            this.handleMultiCheckChange(checked);
          }
        });
      } else {
        panel.handleExpand(node);
      }
    },

    handleCheckChange() {
      const { panel, value, node } = this;
      panel.handleCheckChange(value);
      panel.handleExpand(node);
    },

    handleMultiCheckChange(checked) {
      this.node.doCheck(checked);
      this.panel.calculateMultiCheckedValue();
    },

    isInPath(pathNodes) {
      const { node } = this;
      const selectedPathNode = pathNodes[node.level - 1] || {};
      return selectedPathNode.uid === node.uid;
    },

    renderPrefix(h) {
      const { isLeaf, isChecked, config } = this;
      const { checkStrictly, multiple } = config;

      if (multiple) {
        return this.renderCheckbox(h);
      } else if (checkStrictly) {
        return this.renderRadio(h);
      } else if (isLeaf && isChecked) {
        return this.renderCheckIcon(h);
      }

      return null;
    },

    renderPostfix(h) {
      const { node, isLeaf } = this;

      if (node.loading) {
        return this.renderLoadingIcon(h);
      } else if (!isLeaf) {
        return this.renderExpandIcon(h);
      }

      return null;
    },

    renderCheckbox(h) {
      const { node, config, isDisabled } = this;
      const events = {
        on: { change: this.handleMultiCheckChange },
        nativeOn: {}
      };

      if (config.checkStrictly) {
        // when every node is selectable, click event should not trigger expand event.
        events.nativeOn.click = stopPropagation;
      }
      return (
        <div class="el-cascader-node__div">
          <el-checkbox
            value={node.checked}
            indeterminate={node.indeterminate}
            disabled={isDisabled}
            {...events}
          ></el-checkbox>
        </div>
      );
    },

    renderRadio(h) {
      let { checkedValue, value, isDisabled } = this;

      // to keep same reference if value cause radio's checked state is calculated by reference comparision;
      if (isEqual(value, checkedValue)) {
        value = checkedValue;
      }

      // const LeafDiv =
      //   isLeaf && isChecked ? (
      //     <i class="bi-iconfont-check el-cascader-node__prefix"></i>
      //   ) : (
      //     ''
      //   );

      // <div class="el-cascader-node__div">
      //   <el-radio
      //     value={checkedValue}
      //     label={value}
      //     disabled={isDisabled}
      //     onChange={this.handleCheckChange}
      //     nativeOnClick={stopPropagation}
      //   >
      //     {/* add an empty element to avoid render label */}
      //     <span></span>
      //   </el-radio>
      //   {LeafDiv}
      // </div>;

      return (
        <div class="el-cascader-node__div">
          <el-radio
            value={checkedValue}
            label={value}
            disabled={isDisabled}
            onChange={this.handleCheckChange}
            nativeOnClick={stopPropagation}
          >
            {/* add an empty element to avoid render label */}
            <span></span>
          </el-radio>
        </div>
      );
    },

    renderCheckIcon(h) {
      return <i class="bi-iconfont-check el-cascader-node__prefix"></i>;
    },

    renderLoadingIcon(h) {
      return <i class="el-icon-loading el-cascader-node__postfix"></i>;
    },

    renderExpandIcon(h) {
      return <i class="bi-iconfont-chevron-right el-cascader-node__postfix"></i>;
    },

    renderContent(h) {
      const { panel, node } = this;
      const render = panel.renderLabelFn;
      const vnode = render ? render({ node, data: node.data }) : null;

      return (
        // <span class="el-cascader-node__label">{ vnode || node.label }</span>
        <el-text-tooltip
          class="el-cascader-node__label"
          content={node.label || vnode}
          width="164px"
        ></el-text-tooltip>
      );
    }
  },

  render(h) {
    const {
      inActivePath,
      inCheckedPath,
      isChecked,
      isLeaf,
      isDisabled,
      config,
      nodeId
    } = this;
    const { expandTrigger, checkStrictly, multiple } = config;
    const disabled = !checkStrictly && isDisabled;
    const events = { on: {} };

    if (expandTrigger === 'click') {
      events.on.click = this.handleExpand;
    } else {
      events.on.mouseenter = (e) => {
        this.handleExpand();
        this.$emit('expand', e);
      };
      events.on.focus = (e) => {
        this.handleExpand();
        this.$emit('expand', e);
      };
    }
    if (isLeaf && !isDisabled && !checkStrictly && !multiple) {
      events.on.click = this.handleCheckChange;
    }

    return (
      <li
        role="menuitem"
        id={nodeId}
        aria-expanded={inActivePath}
        tabindex={disabled ? null : -1}
        class={{
          'el-cascader-node': true,
          'is-selectable': checkStrictly,
          'in-active-path': inActivePath,
          'in-checked-path': inCheckedPath,
          'is-active': isChecked,
          'is-disabled': disabled
        }}
        {...events}
      >
        {this.renderPrefix(h)}
        {this.renderContent(h)}
        {this.renderPostfix(h)}
      </li>
    );
  }
};
</script>
