<template>
  <RawSelect
    v-bind="$props"
    :open="isDatalistOpen"
    @select="onSelect"
    @click="onSelectClick"
  >
    <template #input>
      <input
        ref="inputElement"
        type="text"
        role="input"
        readonly
        :value="displayValue"
        :placeholder="placeholder"
        :required="required"
        :disabled="disabled"
        @keyup.down="openDatalist"
      />
      <span class="icon-toggle-container">
        <ChevronUp v-if="isDatalistOpen" class="icon-toggle-button" />
        <ChevronDown v-else class="icon-toggle-button" />
      </span>
    </template>
  </RawSelect>
</template>

<script lang="ts" setup>
import { ChevronDown, ChevronUp } from 'lucide-vue-next';
import { computed, Ref, ref, watch } from 'vue';
import _ from 'lodash';
import { InputOption } from '@/models';
import { FieldComponentProps } from '@/plugins/field/field-component.model';
import RawSelect from './RawSelect.vue';
import { onClickOutside, onKeyUp } from '@vueuse/core';

export interface Props extends FieldComponentProps {
  options: InputOption[];
  optional?: boolean;
  placeholder?: string;
  open?: boolean;
}

const props = withDefaults(defineProps<Props>(), {
  label: '',
  disabled: false,
  required: false,
  small: false,
  open: false,
});

const emits = defineEmits<{
  select: [value: any];
}>();

const modelValue = defineModel<any>('modelValue', { required: true });

const inputElement: Ref<HTMLElement | null> = ref(null);
const isDatalistOpen = ref(props.open);

const closeDatalist = () => {
  isDatalistOpen.value = false;
};
const openDatalist = () => {
  if (!props.disabled) {
    isDatalistOpen.value = true;
    setFocus();
  }
};

onClickOutside(inputElement, closeDatalist, {
  ignore: ['.datalist-option', '.icon-toggle-button'],
});
onKeyUp('Escape', closeDatalist);
onKeyUp('Tab', closeDatalist);

const displayValue = computed(() => {
  const option = props.options.find((o) =>
    _.isEqual(o.value, modelValue.value),
  );
  if (option) return option.label;
  return '';
});

const setFocus = () => {
  if (inputElement.value) {
    (inputElement.value as any).focus();
  }
};

const onSelect = (option: any) => {
  modelValue.value = option.value;
  emits('select', option.value);
  setFocus();
  closeDatalist();
};

const onSelectClick = () => {
  if (!props.disabled) {
    isDatalistOpen.value = !isDatalistOpen.value;
    if (isDatalistOpen) {
      setFocus();
    }
  }
};

defineExpose({
  setFocus,
});
</script>

<style lang="scss" scoped>
.field__input {
  .icon-toggle {
    &-container {
      height: 100%;
      display: flex;
      align-items: center;

      &:hover {
        cursor: pointer;
      }
    }
    &-button {
      width: 1em;
      margin: 0 var(--field-padding);
      display: block;
    }
  }

  input {
    border: none;
    background-color: transparent;
    caret-color: transparent;
    cursor: pointer;
    outline: none;
    appearance: none;
    margin: 0;
    padding: 0;
    font: inherit;
    color: inherit;
    line-height: 1;
    width: 100%;
    height: 100%;
  }
}
</style>
