<script setup>
import { computed, ref } from 'vue'

const props = defineProps({
  modelValue: { type: Array, default: () => [] },
  placeholder: { type: String, default: '태그 입력 후 Enter' },
  disabled: { type: Boolean, default: false },
  maxTags: { type: Number, default: 30 },
  maxTagLength: { type: Number, default: 40 },
})

const emit = defineEmits(['update:modelValue'])

const draft = ref('')
const isComposing = ref(false)

const normalizedTags = computed(() =>
  Array.from(
    new Set(
      (Array.isArray(props.modelValue) ? props.modelValue : [])
        .map((tag) => String(tag || '').trim().replace(/^#/, '').slice(0, props.maxTagLength))
        .filter(Boolean)
    )
  ).slice(0, props.maxTags)
)

function commitTags(nextTags) {
  emit(
    'update:modelValue',
    Array.from(
      new Set(
        (nextTags || [])
          .map((tag) => String(tag || '').trim().replace(/^#/, '').slice(0, props.maxTagLength))
          .filter(Boolean)
      )
    ).slice(0, props.maxTags)
  )
}

function addDraftTag() {
  if (props.disabled) return
  const nextTag = String(draft.value || '').trim().replace(/^#/, '').slice(0, props.maxTagLength)
  if (!nextTag) return
  commitTags([...normalizedTags.value, nextTag])
  draft.value = ''
}

function removeTag(tag) {
  if (props.disabled) return
  commitTags(normalizedTags.value.filter((entry) => entry !== tag))
}

function handleKeydown(event) {
  if (event.isComposing || isComposing.value) return
  if (event.key === 'Enter') {
    event.preventDefault()
    addDraftTag()
    return
  }

  if (event.key === 'Backspace' && !draft.value && normalizedTags.value.length) {
    removeTag(normalizedTags.value[normalizedTags.value.length - 1])
  }
}

function handleBlur() {
  if (isComposing.value) return
  addDraftTag()
}

function handleCompositionStart() {
  isComposing.value = true
}

function handleCompositionEnd() {
  isComposing.value = false
}
</script>

<template>
  <div class="tagBadgeInput" :class="{ 'tagBadgeInput--disabled': disabled }">
    <div v-if="normalizedTags.length" class="tagBadgeInput__list">
      <span v-for="tag in normalizedTags" :key="tag" class="tagBadgeInput__badge">
        <span>#{{ tag }}</span>
        <button class="tagBadgeInput__remove" type="button" :disabled="disabled" @click="removeTag(tag)">X</button>
      </span>
    </div>
    <input
      v-model="draft"
      class="tagBadgeInput__input"
      type="text"
      :placeholder="placeholder"
      :disabled="disabled || normalizedTags.length >= maxTags"
      :maxlength="maxTagLength"
      @keydown="handleKeydown"
      @blur="handleBlur"
      @compositionstart="handleCompositionStart"
      @compositionend="handleCompositionEnd"
    />
  </div>
</template>

<style scoped>
.tagBadgeInput {
  display: grid;
  gap: 10px;
  padding: 12px 14px;
  border-radius: 14px;
  border: 1px solid color-mix(in srgb, var(--theme-border-strong) 72%, rgba(255, 255, 255, 0.08));
  background: color-mix(in srgb, var(--theme-surface-soft) 82%, rgba(255, 255, 255, 0.02));
}

.tagBadgeInput--disabled {
  opacity: 0.72;
}

.tagBadgeInput__list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.tagBadgeInput__badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 11px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--theme-accent-soft) 55%, rgba(255, 255, 255, 0.06));
  color: var(--theme-text);
  font-size: 12px;
  font-weight: 700;
}

.tagBadgeInput__remove {
  border: none;
  background: transparent;
  color: inherit;
  font-size: 11px;
  font-weight: 800;
  cursor: pointer;
  padding: 0;
}

.tagBadgeInput__input {
  width: 100%;
  min-width: 0;
  border: none;
  outline: none;
  background: transparent;
  color: var(--theme-text);
  font: inherit;
}

.tagBadgeInput__input::placeholder {
  color: var(--theme-text-soft);
}
</style>
