import {
  defineComponent,
  PropType,
  ref,
  computed,
} from 'vue';
import cloneDeep from 'lodash/cloneDeep';
import clickOutset from '@/directives/clickOutset';
import CascaderItem from './cascaderItem';
import './_style.scss';

export interface OptionsItem {
  id?: number,
  pid?: number,
  label: string;
  value: string;
  children?: OptionsItem[];
}

export default defineComponent({
  name: 'Cascader',
  props: {
    options: {
      type: Array as PropType<OptionsItem[]>,
      default: () => [],
    },
    modelValue: {
      type: Array as PropType<OptionsItem[]>,
      default: () => ([] as OptionsItem[]),
    },
    lazyLoad: {
      type: Function as PropType<(node: unknown, resolve: (data: unknown[]) => void) => void>,
    },
  },
  emits: [
    'update:modelValue',
    'update:options',
  ],
  directives: {
    'click-outset': clickOutset,
  },
  setup(props, { emit }) {
    // 定义一个变量用来显示隐藏级联面板
    const isVisible = ref(false);

    // 计算显示的title
    const title = computed(() => props.modelValue.map((item) => item.label).join(' / '));

    // 点击标题可切换面板显示/隐藏
    const toggle = () => {
      isVisible.value = !isVisible.value;
    };

    // 点击cascader外部区域关闭面板
    const close = () => {
      isVisible.value = false;
    };

    // 更新options数据 -- 根据当前id去查找options中对应id项添加children属性
    const updateOptions = (id: number, children: any) => {
      // 由于这里的options是一个树形数据 --> 我先采用递归的方式去里面查找
      const options = cloneDeep(props.options);
      // 涉及到树的遍历问题 --> 递归肯定能实现但是我们用树的广度搜索
      // 广度搜索的原理就是一层一层的顺序遍历每个节点所以我们的得将每层的节点取出放入一个栈中
      let stack: any[] = [...options]; // 存放所有节点的栈
      let index = 0; // 当前遍历的节点索引
      let current; // 当前遍历的节点
      // eslint-disable-next-line
      while (current = stack[index]) {
        // 找到了
        if (current.id === id) {
          // 给当前项添加children属性
          current.lazy = false;
          current.children = children;
        } else if (current.children && current.children.length > 0) {
          // 没找到，有孩子，将孩子节点存放栈尾部
          stack = stack.concat(current.children);
        }
        // 查找完成指针向前一位
        index += 1;
      }
      emit('update:options', options);
    };

    // 监听CascaderItem组件选中事件
    const change = (value: any[]) => {
      const currentItem = value[value.length - 1];
      console.log(currentItem);
      if (props.lazyLoad && typeof props.lazyLoad === 'function') {
        props.lazyLoad(currentItem, (children) => {
          if (children && children.length === 0) {
            close();
          }
          // 更新外界options选项
          updateOptions(currentItem.id, children);
          // 更新外部value值
          currentItem.children = children;
          emit('update:modelValue', value);
        });
      } else {
        if (!currentItem.children || currentItem.children.length === 0) {
          close();
        }
        emit('update:options', props.options);
        emit('update:modelValue', value);
      }
    };

    return () => (
      <div class="cascader" v-click-outset={close}>
        <div class="cascader-title" title={title.value} onClick={toggle}>
          { title.value }
        </div>
        {isVisible.value ? (
          <div class="cascader-panel">
            {
              props.options.length === 0 ? <div class="empty-data">暂无数据！</div>
                : <CascaderItem
                options={props.options}
                value={props.modelValue}
                level={0}
                onChange={change}
                lazy={!!props.lazyLoad}
              ></CascaderItem>
            }
          </div>
        ) : null}
      </div>
    );
  },
});
