import Fuse from "fuse.js";
import { h, isRef, ref, unref, watch } from "vue";
import { elementsAsOptions } from "@/_utils";
import { NText, type SelectRenderLabel, type SelectRenderTag } from "naive-ui";

export const useFuzzySearch = (options: readonly string[]) => {
  const optionsRef = ref(elementsAsOptions(unref(options)));

  const fuse = new Fuse(options, {
    keys: ["label", { name: "description", weight: 0.8 }],
    ignoreLocation: true,
  });

  if (isRef(options)) {
    watch(options, (o) => {
      fuse.setCollection(o);
      optionsRef.value = elementsAsOptions(o);
    });
  }

  // @todo debounce minimally
  function search(pattern: string) {
    if (pattern === "") {
      reset();
    } else {
      const search = fuse.search(pattern);
      const elements = search.map((match) => ({ ...match.item }));
      optionsRef.value = elementsAsOptions(elements);
    }
  }

  function reset() {
    optionsRef.value = elementsAsOptions(options);
  }

  const renderLabel: SelectRenderLabel = (option) => {
    if (option.type === "group") return option.label;
    return h("div", { className: "flex flex-col max-w-[550px] my-2 gap-1" }, [
      h("div", option?.label),
      h(NText, { depth: 3, tag: "div" }, { default: () => option?.description }),
    ]);
  };

  const renderTag: SelectRenderTag = ({ option }) => {
    return h("div", option.label);
  };

  return {
    search,
    reset,
    matches: optionsRef,
    renderLabel,
    renderTag,
  };
};
