<template>
  <div class="w-full">
    <Combobox v-model="selected" :disabled="disabled" multiple>
      <ComboboxLabel>{{ title }}</ComboboxLabel>
      <div class="relative mt-1">
        <ComboboxInput
          class="rounded-md shadow-sm relative block w-full px-3 py-2 border border-gray-300 focus:border-primary placeholder-gray-500 text-gray-900 rounded-b-md focus:outline-none focus:ring-0 focus:z-10 sm:text-sm resize-none"
          @input="query = $event.target.value"
        />
        <ComboboxButton class="absolute inset-y-0 right-0 flex items-center pr-2">
          <ChevronUpDownIcon class="h-5 w-5 text-gray-400" aria-hidden="true" />
        </ComboboxButton>
        <TransitionRoot
          leave="transition ease-in duration-100"
          leaveFrom="opacity-100"
          leaveTo="opacity-0"
          @after-leave="query = ''"
        >
          <ComboboxOptions
            class="absolute mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-md ring-1 ring-black/5 focus:outline-none sm:text-sm"
          >
            <ComboboxOption v-if="loading || deferingSearch" as="template" disabled>
              <li class="flex flex-row gap-2 text-text relative cursor-default select-none py-2 pl-3 pr-4">
                <Spinner />
                <span class="font-normal block truncate">suche</span>
              </li>
            </ComboboxOption>
            <ComboboxOption v-else-if="filtered.length === 0 && query == ''" as="template" disabled>
              <li class="text-text relative cursor-default select-none py-2 pl-3 pr-4">
                <span class="font-normal block truncate">tippe, um zu suchen...</span>
              </li>
            </ComboboxOption>
            <ComboboxOption v-else-if="filtered.length === 0" as="template" disabled>
              <li class="text-text relative cursor-default select-none py-2 pl-3 pr-4">
                <span class="font-normal block truncate">Keine Auswahl gefunden.</span>
              </li>
            </ComboboxOption>

            <ComboboxOption
              v-if="!(loading || deferingSearch)"
              v-for="member in filtered"
              as="template"
              :key="member.id"
              :value="member.id"
              v-slot="{ selected, active }"
            >
              <li
                class="relative cursor-default select-none py-2 pl-10 pr-4"
                :class="{
                  'bg-primary text-white': active,
                  'text-gray-900': !active,
                }"
              >
                <span class="block truncate" :class="{ 'font-medium': selected, 'font-normal': !selected }">
                  {{ member.firstname }} {{ member.lastname }} {{ member.nameaffix }}
                </span>
                <span
                  v-if="selected"
                  class="absolute inset-y-0 left-0 flex items-center pl-3"
                  :class="{ 'text-white': active, 'text-primary': !active }"
                >
                  <CheckIcon class="h-5 w-5" aria-hidden="true" />
                </span>
              </li>
            </ComboboxOption>
          </ComboboxOptions>
        </TransitionRoot>
      </div>
    </Combobox>
  </div>
</template>

<script setup lang="ts">
import { defineComponent, type PropType } from "vue";
import { mapState, mapActions } from "pinia";
import {
  Combobox,
  ComboboxLabel,
  ComboboxInput,
  ComboboxButton,
  ComboboxOptions,
  ComboboxOption,
  TransitionRoot,
} from "@headlessui/vue";
import { CheckIcon, ChevronUpDownIcon } from "@heroicons/vue/20/solid";
import { useMemberStore } from "@/stores/admin/club/member/member";
import type { MemberViewModel } from "@/viewmodels/admin/club/member/member.models";
import difference from "lodash.difference";
import Spinner from "../Spinner.vue";
</script>

<script lang="ts">
export default defineComponent({
  props: {
    modelValue: {
      type: Array as PropType<Array<number>>,
      default: [],
    },
    title: String,
    disabled: {
      type: Boolean,
      default: false,
    },
  },
  emits: ["update:model-value", "add:difference", "remove:difference", "add:member", "add:memberByArray"],
  watch: {
    modelValue() {
      if (this.initialLoaded) return;
      this.initialLoaded = true;
      this.loadMembersInitial();
    },
    query() {
      this.deferingSearch = true;
      clearTimeout(this.timer);
      this.timer = setTimeout(() => {
        this.deferingSearch = false;
        this.search();
      }, 600);
    },
  },
  data() {
    return {
      initialLoaded: false as boolean,
      loading: false as boolean,
      deferingSearch: false as boolean,
      timer: undefined as any,
      query: "" as string,
      filtered: [] as Array<MemberViewModel>,
    };
  },
  computed: {
    selected: {
      get() {
        return this.modelValue;
      },
      set(val: Array<number>) {
        this.$emit("update:model-value", val);
        if (this.modelValue.length < val.length) {
          let diff = difference(val, this.modelValue);
          if (diff.length != 1) return;
          this.$emit("add:difference", diff[0]);
          this.$emit("add:member", this.getMemberFromSearch(diff[0]));
        } else {
          let diff = difference(this.modelValue, val);
          if (diff.length != 1) return;
          this.$emit("remove:difference", diff[0]);
        }
      },
    },
  },
  mounted() {
    this.loadMembersInitial();
  },
  methods: {
    ...mapActions(useMemberStore, ["searchMembers", "getMembersByIds"]),
    search() {
      this.filtered = [];
      if (this.query == "") return;
      this.loading = true;
      this.searchMembers(this.query)
        .then((res) => {
          this.filtered = res.data;
        })
        .catch((err) => {})
        .finally(() => {
          this.loading = false;
        });
    },
    getMemberFromSearch(id: number) {
      return this.filtered.find((f) => f.id == id);
    },
    loadMembersInitial() {
      if (this.modelValue.length == 0) return;
      this.getMembersByIds(this.modelValue)
        .then((res) => {
          this.$emit("add:memberByArray", res.data);
        })
        .catch(() => {});
    },
  },
});
</script>
