<template>
  <div class="relative" :class="{ 'with-count': showCount }">
    <input
      v-model="newTag"
      type="text"
      :list="id"
      placeholder="Теги"
      class="w-full focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md"
      autocomplete="off"
      :style="{ 'padding-left': `${paddingLeft}px` }"
      @keydown.prevent.enter="addTag(newTag)"
      @blur.prevent="addTag(newTag)"
    />

    <datalist v-if="options" :id="id">
      <option v-for="option in availableOptions" :key="option"
              :value="option"
      >
        {{ option }}
      </option>
    </datalist>

    <ul ref="tagsUl" class="tags">
      <li
        v-for="(tag, index) in tags"
        :key="tag"
        class=""
        :class="{ 'duplicate-shake': tag === duplicate }"
      >
        <span class="inline-flex rounded-full items-center py-0.5 pl-2.5 pr-1 text-sm font-medium bg-orange text-indigo-300">
          {{ tag }}
          <button type="button" class="flex-shrink-0 ml-0.5 h-4 w-4 rounded-full inline-flex items-center justify-center text-indigo-300 hover:bg-indigo-200 hover:text-white focus:outline-none focus:bg-indigo-200 focus:text-white"
                  @click="removeTag(index)"
          >
            <span class="sr-only">Удалить</span>
            <svg class="h-2 w-2" stroke="currentColor"
                 fill="none" viewBox="0 0 8 8"
            >
              <path stroke-linecap="round" stroke-width="1.5"
                    d="M1 1l6 6m0-6L1 7"
              />
            </svg>
          </button>
        </span>
      </li>
    </ul>
    <div v-if="showCount" class="count">
      <span>{{ tags.length }}</span> tags
    </div>
  </div>
</template>
<script>
import { toRef, ref, watch, nextTick, onMounted, computed } from 'vue'
export default {
    props: {
        name: { type: String, default: '' },
        modelValue: { type: Array, default: () => [] },
        options: { type: [Array, Boolean], default: false },
        allowCustom: { type: Boolean, default: true },
        showCount: { type: Boolean, default: false },
    },
    setup(props, { emit }) {
    // Tags
        const  tags  = toRef(props, 'modelValue')

        const newTag = ref('')
        const id = Math.random().toString(36).substring(7)

        const addTag = (tag) => {
            if (!tag) return // prevent empty tag
            // only allow predefined tags when allowCustom is false
            if (!props.allowCustom && !props.options.includes(tag)) return
            // return early if duplicate
            if (tags.value.includes(tag)) {
                handleDuplicate(tag)
                return
            }
            tags.value.push(tag)
            newTag.value = '' // reset newTag
        }
        const removeTag = (index) => {
            tags.value.splice(index, 1)
        }

        // handling duplicates
        const duplicate = ref(null)
        const handleDuplicate = (tag) => {
            duplicate.value = tag
            setTimeout(() => (duplicate.value = null), 1000)
            newTag.value = ''
        }

        // positioning and handling tag change
        const paddingLeft = ref(10)
        const tagsUl = ref(null)
        const onTagsChange = () => {
            // position cursor
            const extraCushion = 15
            paddingLeft.value = tagsUl.value.clientWidth + extraCushion
            // scroll to end of tags
            tagsUl.value.scrollTo(tagsUl.value.scrollWidth, 0)
            // emit value on tags change
            emit('update:modelValue', tags.value)
        }
        watch(tags, () => nextTick(onTagsChange), { deep: true })
        onMounted(onTagsChange)

        // options
        const availableOptions = computed(() => {
            if (!props.options) return false
            return props.options.filter((option) => !tags.value.includes(option))
        })

        return {
            tags,
            newTag,
            addTag,
            removeTag,
            paddingLeft,
            tagsUl,
            availableOptions,
            id,
            duplicate,
        }
    },
}
</script>
<style scoped>

ul {
  list-style: none;
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 0;
  padding: 0;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 10px;
  max-width: 75%;
  overflow-x: auto;
}

@keyframes shake {
  10%,
  90% {
    transform: scale(0.9) translate3d(-1px, 0, 0);
  }

  20%,
  80% {
    transform: scale(0.9) translate3d(2px, 0, 0);
  }

  30%,
  50%,
  70% {
    transform: scale(0.9) translate3d(-4px, 0, 0);
  }

  40%,
  60% {
    transform: scale(0.9) translate3d(4px, 0, 0);
  }
}
.duplicate-shake {
  animation: shake 1s;
}
.count {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  right: 10px;
  display: block;
  font-size: 0.8rem;
  white-space: nowrap;
}
.count span {
  background: #eee;
  padding: 2px;
  border-radius: 2px;
}
.with-count input {
  padding-right: 60px;
}
.with-count ul {
  max-width: 60%;
}
</style>
