<script setup lang="ts">
import type { SelectValue } from 'ant-design-vue/es/select';

import type { ApiConfig } from '../types';

import { computed, type PropType, ref, unref, watch, watchEffect } from 'vue';

import { isFunction } from '@vben/utils';

import { useVModel } from '@vueuse/core';
import { TreeSelect } from 'ant-design-vue';

import { Icon } from '#/components/icon';
import { get } from '#/utils';

import { createApiFunction } from '../helper';

const props = defineProps({
  value: {
    type: [String, Number, Array] as PropType<SelectValue>,
    default: undefined,
  },
  api: {
    type: Object as PropType<ApiConfig>,
    default: () => ({
      type: 'none',
      method: 'get',
      params: {},
      result: '',
      url: null,
    }),
  },
  fieldNames: {
    type: Object as PropType<{
      children: string;
      label: string;
      value: string;
    }>,
    default: () => ({ label: 'label', value: 'value', children: 'children' }),
  },
  immediate: {
    type: Boolean,
    default: true,
  },
  showSearch: {
    type: Boolean,
    default: false,
  },
});
const emit = defineEmits(['update:value', 'optionsChange']);
const modelValue = useVModel(props, 'value', emit, {
  defaultValue: props.value,
  passive: true,
});
const treeData = ref<Record<string, any>[]>([]);
const loading = ref(false);
const isFirstLoad = ref(true);
const getTreeData = computed(() => {
  return unref(treeData);
});

const emitChange = () => {
  emit('optionsChange', unref(treeData));
};

const fetch = async () => {
  const api = createApiFunction({ ...props.api });
  if (!api || !isFunction(api)) return;
  try {
    loading.value = true;
    const res = await api(props.api.params);
    if (Array.isArray(res)) {
      treeData.value = res || [];
    } else {
      treeData.value = props.api.result ? get(res, props.api.result) : [];
    }
    emitChange();
  } catch (error) {
    console.warn(error);
  } finally {
    loading.value = false;
  }
};
async function handleFetch() {
  if (!props.immediate && unref(isFirstLoad)) {
    await fetch();
    isFirstLoad.value = false;
  }
}
watchEffect(() => {
  props.immediate && fetch();
});

watch(
  () => props.api.params,
  () => {
    !isFirstLoad.value && fetch();
  },
  { deep: true },
);
</script>

<template>
  <TreeSelect
    v-model:value="modelValue"
    :field-names="fieldNames"
    :show-search="showSearch"
    :tree-data="getTreeData"
    :tree-node-filter-prop="fieldNames.label"
    class="w-full"
    @dropdown-visible-change="handleFetch"
  >
    <template v-for="item in Object.keys($slots)" #[item]="data">
      <slot :name="item" v-bind="data || {}"></slot>
    </template>
    <template v-if="loading" #suffixIcon>
      <Icon icon="ant-design:loading-outlined" spin />
    </template>
  </TreeSelect>
</template>
