<script lang="ts" setup>
import type { TreeProps } from 'ant-design-vue';

import type { PropType } from 'vue';

import type { ApiConfig } from '#/components/form/types';

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

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

import { Input, Tree } from 'ant-design-vue';

import { createApiFunction } from '#/components/form/helper';
import { Icon } from '#/components/icon';
import { filter, get, treeToList } from '#/utils';

const props = defineProps({
  multiple: {
    type: Boolean as PropType<boolean>,
    default: true,
  },
  title: {
    type: String as PropType<string>,
    default: '',
  },
  api: {
    type: Object as PropType<ApiConfig>,
    default: () => ({
      type: 'none',
      method: 'get',
      params: {},
      result: '',
      url: null,
    }),
  },
  fieldNames: {
    type: Object as PropType<{ children: any; label: string; value: string }>,
    default: () => ({ label: 'label', value: 'value', children: null }),
  },
  expandOnSearch: {
    type: Boolean,
    default: true,
  },
  immediate: {
    type: Boolean,
    default: true,
  },
});

const emit = defineEmits(['update:searchValue']);

const state = reactive<{
  autoExpandParent: boolean;
  expandedKeys: (number | string)[];
}>({
  expandedKeys: [],
  autoExpandParent: true,
});

const searchListData = ref('');
const searchState = reactive({
  startSearch: false,
  searchText: '',
  searchData: [] as TreeProps['treeData'],
});

const treeDataRef = ref<TreeProps['treeData']>([]);

const loading = ref(false);
const isFirstLoad = ref(true);
const handleExpand = (keys: string[]) => {
  state.expandedKeys = keys;
  state.autoExpandParent = false;
};

// const getParentKey = (
//   key: number | string,
//   tree: TreeProps['treeData'],
// ): number | string | undefined => {
//   let parentKey;
//   tree &&
//     tree.forEach((node) => {
//       if (node.children) {
//         if (node.children.some((item) => item.key === key)) {
//           parentKey = node.key;
//         } else if (getParentKey(key, node.children)) {
//           parentKey = getParentKey(key, node.children);
//         }
//       }
//     });
//   return parentKey;
// };

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)) {
      treeDataRef.value = res;
    } else {
      treeDataRef.value = props.api.result ? get(res, props.api.result) : [];
    }
  } catch (error) {
    console.warn(error);
  } finally {
    loading.value = false;
  }
};

watchEffect(() => {
  props.immediate && fetch();
});

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

const setExpandedKeys = (keys: (number | string)[]) => {
  state.expandedKeys = keys;
};

// const getExpandedKeys = () => {
//   return state.expandedKeys;
// };

const handleSearch = (searchValue: string) => {
  if (searchValue !== searchState.searchText)
    searchState.searchText = searchValue;
  emit('update:searchValue', searchValue);
  if (!searchValue) {
    searchState.startSearch = false;
    return;
  }

  searchState.startSearch = true;
  const { fieldNames, expandOnSearch } = props;

  const matchedKeys: string[] = [];
  searchState.searchData = filter(
    unref(treeDataRef),
    (node) => {
      const result = node[fieldNames.label]?.includes(searchValue) ?? false;
      if (result) {
        matchedKeys.push(node[fieldNames.value]);
      }
      return result;
    },
    fieldNames,
  );

  if (expandOnSearch) {
    const expandKeys = treeToList(searchState.searchData).map((val: any) => {
      return val[fieldNames.value];
    });
    if (expandKeys && expandKeys.length > 0) {
      setExpandedKeys(expandKeys);
    }
  }

  // if (checkOnSearch && checkable && matchedKeys.length > 0) {
  //   setCheckedKeys(matchedKeys);
  // }

  // if (selectedOnSearch && matchedKeys.length > 0) {
  //   setSelectedKeys(matchedKeys);
  // }
};
function handleKeyChange(v: any) {
  handleSearch(v.target.value);
}

const getTreeData = computed((): TreeProps['treeData'] =>
  searchState.startSearch ? searchState.searchData : unref(treeDataRef),
);
</script>
<template>
  <div class="h-full">
    <div class="flex h-[30px] items-center justify-between">
      <div>
        {{ title }}
      </div>
      <div>
        <Icon icon="uil:ellipsis-v" />
      </div>
    </div>
    <div style="height: calc(100% - 30px)" class="overflow-y-auto">
      <div class="h-[35px]">
        <Input
          style="height: 35px; padding: 3px 2px 3px 10px"
          v-model:value="searchListData"
          @change="handleKeyChange"
          placeholder="输入关键字搜索"
        />
      </div>
      <Tree
        :expanded-keys="state.expandedKeys"
        :auto-expand-parent="state.autoExpandParent"
        :tree-data="getTreeData"
        :field-names="{
          title: fieldNames.label,
          key: fieldNames.value,
          children: fieldNames.children,
        }"
        style="height: calc(100% - 35px)"
        @expand="handleExpand"
      >
        <template #title="{ title }">
          <span v-if="title.indexOf(searchListData) > -1">
            {{ title.substring(0, title.indexOf(searchListData)) }}
            <span style="color: #f50">{{ searchListData }}</span>
            {{
              title.substring(
                title.indexOf(searchListData) + searchListData.length,
              )
            }}
          </span>
          <span v-else>{{ title }}</span>
        </template>
      </Tree>
    </div>
  </div>
</template>
