<template>
  <div class="floating-input-wrapper">
    <input
      :id="id"
      :type="type"
      :value="modelValue"
      @input="handleInput"
      @blur="handleBlur"
      @focus="handleFocus"
      class="floating-input"
      :class="inputClasses"
      placeholder=" "
      :disabled="disabled"
      :required="required"
    />
    <label :for="id" class="floating-label" :class="{ 'text-error': error }">
      {{ label }}
      <span v-if="required" class="text-error">*</span>
    </label>
    <transition name="slide-down">
      <div v-if="error" class="input-error">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-4 h-4">
          <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd" />
        </svg>
        {{ error }}
      </div>
    </transition>
    <transition name="slide-down">
      <div v-if="hint && !error" class="input-hint">{{ hint }}</div>
    </transition>
  </div>
</template>

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

interface Props {
  id: string
  label: string
  modelValue: string | number
  type?: string
  error?: string
  hint?: string
  disabled?: boolean
  required?: boolean
}

const props = withDefaults(defineProps<Props>(), {
  type: 'text',
  disabled: false,
  required: false
})

const emit = defineEmits<{
  'update:modelValue': [value: string]
  blur: []
  focus: []
}>()

const isFocused = ref(false)

const inputClasses = computed(() => ({
  'border-error': props.error,
  'border-primary': isFocused.value && !props.error,
  'opacity-60 cursor-not-allowed': props.disabled
}))

const handleInput = (event: Event) => {
  const target = event.target as HTMLInputElement
  emit('update:modelValue', target.value)
}

const handleBlur = () => {
  isFocused.value = false
  emit('blur')
}

const handleFocus = () => {
  isFocused.value = true
  emit('focus')
}
</script>

<style scoped>
.floating-input-wrapper {
  position: relative;
  margin-bottom: 1.5rem;
}

.floating-input {
  width: 100%;
  padding: 1rem 0.75rem 0.5rem;
  border: 2px solid hsl(var(--bc) / 0.2);
  border-radius: 0.5rem;
  background: hsl(var(--b1));
  color: hsl(var(--bc));
  font-size: 1rem;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
  outline: none;
}

.floating-input:focus {
  border-color: hsl(var(--p));
  box-shadow: 0 0 0 3px hsl(var(--p) / 0.1);
}

.floating-input.border-error {
  border-color: hsl(var(--er));
}

.floating-input.border-error:focus {
  box-shadow: 0 0 0 3px hsl(var(--er) / 0.1);
}

.floating-label {
  position: absolute;
  left: 0.75rem;
  top: 1rem;
  font-size: 1rem;
  color: hsl(var(--bc) / 0.6);
  transition: all 0.2s ease;
  pointer-events: none;
  background: hsl(var(--b1));
  padding: 0 0.25rem;
}

.floating-input:focus ~ .floating-label,
.floating-input:not(:placeholder-shown) ~ .floating-label {
  top: -0.5rem;
  left: 0.5rem;
  font-size: 0.75rem;
  font-weight: 600;
}

.floating-input:focus ~ .floating-label {
  color: hsl(var(--p));
}

.floating-label.text-error {
  color: hsl(var(--er));
}

.input-error {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  margin-top: 0.375rem;
  font-size: 0.875rem;
  color: hsl(var(--er));
}

.input-hint {
  margin-top: 0.375rem;
  font-size: 0.875rem;
  color: hsl(var(--bc) / 0.6);
}

/* Transition animations */
.slide-down-enter-active,
.slide-down-leave-active {
  transition: all 0.2s ease;
}

.slide-down-enter-from {
  opacity: 0;
  transform: translateY(-4px);
}

.slide-down-leave-to {
  opacity: 0;
  transform: translateY(-4px);
}
</style>
