<template>
  <div class="flex flex-wrap items-center input-field gap-1" @click="focusInput">
    <div v-for="(chip, i) in internalValue" :key="i" class="flex gap-2.5 items-center bg-cyan rounded py-1 px-2" role="listitem">
      <span class="text-xs text-white">{{ chip }}</span>
      <button type="button" class="text-xs cursor-pointer text-white font-light font-default not-italic hover:text-gray-50" @click.stop="deleteChip(i)" aria-label="Remove tag">×</button>
    </div>
    <input ref="inputRef" class="outline-none border-none p-1 text-gray-300 min-w-[60px] flex-grow" :placeholder="placeholder" v-model.trim="currentInput" @keydown="handleKeydown" @paste="handlePaste" :maxlength="maxChipLength" aria-label="Add new tag" />
  </div>
</template>

<script setup lang="ts">
import { ref, watch } from 'vue'
import type { Ref } from 'vue'

interface Props {
  modelValue?: string[]
  maxChips?: number
  maxChipLength?: number
  placeholder?: string
  allowDuplicates?: boolean
}

const props = withDefaults(defineProps<Props>(), {
  modelValue: () => [],
  maxChips: 10,
  maxChipLength: 20,
  placeholder: 'Add tag',
  allowDuplicates: false
})

const emit = defineEmits<{
  (e: 'update:modelValue', value: string[]): void
  (e: 'error', message: string): void
}>()

const currentInput: Ref<string> = ref('')
const internalValue = ref<string[]>([])
const inputRef = ref<HTMLInputElement | null>(null)

watch(
  () => props.modelValue,
  (newValue) => {
    internalValue.value = newValue ? [...newValue] : []
  },
  { immediate: true }
)

const validateChip = (chip: string): boolean => {
  if (!chip) {
    return false
  }

  if (!props.allowDuplicates && internalValue.value.includes(chip)) {
    emit('error', 'Duplicate tags are not allowed')
    return false
  }

  if (internalValue.value.length >= props.maxChips) {
    emit('error', `Maximum ${props.maxChips} tags allowed`)
    return false
  }

  return true
}

const addChip = () => {
  const trimmedInput = currentInput.value.trim()
  if (validateChip(trimmedInput)) {
    internalValue.value.push(trimmedInput)
    emit('update:modelValue', internalValue.value)
    currentInput.value = ''
  }
}

const deleteChip = (index: number) => {
  internalValue.value.splice(index, 1)
  emit('update:modelValue', internalValue.value)
}

const handleKeydown = (event: KeyboardEvent) => {
  switch (event.key) {
    case 'Enter':
      event.preventDefault()
      addChip()
      break
    case 'Backspace':
      if (currentInput.value === '' && internalValue.value.length > 0) {
        deleteChip(internalValue.value.length - 1)
      }
      break
  }
}

const handlePaste = (event: ClipboardEvent) => {
  event.preventDefault()
  const pastedText = event.clipboardData?.getData('text')
  if (pastedText) {
    const chips = pastedText
      .split(/[,\n]/)
      .map((chip) => chip.trim())
      .filter(Boolean)
    chips.forEach((chip) => {
      currentInput.value = chip
      addChip()
    })
  }
}

const focusInput = () => {
  inputRef.value?.focus()
}
</script>
