<template>
  <div :class="wrapperClasses">
    <div class="relative">
      <textarea
        :id="textareaId"
        v-model="modelValue"
        :name="name"
        :placeholder="!hasFloatingLabel ? placeholder : ''"
        :disabled="disabled"
        :readonly="readonly"
        :required="required"
        :rows="rows"
        :cols="cols"
        :maxlength="maxlength"
        :minlength="minlength"
        :wrap="wrap"
        :class="textareaClasses"
        :aria-invalid="hasError"
        :aria-describedby="hasError ? `${textareaId}-error` : undefined"
        @focus="handleFocus"
        @blur="handleBlur"
        @input="handleInput"
        @change="handleChange"
      />

      <label
        v-if="hasFloatingLabel"
        :for="textareaId"
        :class="floatingLabelClasses"
      >
        {{ label }}<span v-if="required" class="text-red-500 ml-1">*</span>
      </label>
    </div>

    <Transition name="error-fade">
      <div
        v-if="hasError && errorMessage"
        :id="`${textareaId}-error`"
        class="mt-1 text-sm text-red-600"
        role="alert"
        aria-live="polite"
      >
        {{ errorMessage }}
      </div>
    </Transition>
  </div>
</template>

<script setup lang="ts">
import { computed, ref, useId, nextTick } from 'vue'
import type { TextareaProps, TextareaEmits } from '@/types/components'

const props = withDefaults(defineProps<TextareaProps>(), {
  disabled: false,
  readonly: false,
  required: false,
  error: false,
  size: 'md',
  variant: 'default',
  rows: 4,
  wrap: 'soft',
  autoResize: false
})

const emit = defineEmits<TextareaEmits>()

// Generate unique ID for the textarea
const textareaId = useId()

// Reactive state
const isFocused = ref(false)
const hasValue = computed(() => props.modelValue != null && props.modelValue !== '')
const hasError = computed(() => props.error || !!props.errorMessage)
const hasFloatingLabel = computed(() => !!props.label)

// Handle v-model updates
const modelValue = computed({
  get: () => props.modelValue || '',
  set: (value) => emit('update:modelValue', value)
})

// Event handlers
const handleFocus = (event: FocusEvent) => {
  isFocused.value = true
  emit('focus', event)
}

const handleBlur = (event: FocusEvent) => {
  isFocused.value = false
  emit('blur', event)
}

const handleInput = async (event: Event) => {
  const target = event.target as HTMLTextAreaElement
  emit('input', event)
  emit('update:modelValue', target.value)

  // Auto-resize functionality
  if (props.autoResize) {
    await nextTick()
    target.style.height = 'auto'
    target.style.height = `${target.scrollHeight}px`
  }
}

const handleChange = (event: Event) => {
  emit('change', event)
}

// Dynamic classes
const wrapperClasses = computed(() => {
  const classes = ['titan-textarea-wrapper', 'relative']

  if (props.class) {
    classes.push(props.class)
  }

  return classes.join(' ')
})

const textareaClasses = computed(() => {
  const classes = [
    // Base styles - full border like Figma design
    'w-full',
    'border',
    'rounded-sm',
    'bg-transparent',
    'px-4',
    'py-3',
    'text-base',
    'leading-6',
    'transition-all',
    'duration-200',
    'ease-in-out',
    'outline-none',
    'appearance-none',
    'shadow-sm',

    // Typography - inherit from parent
    'font-normal',

    // Focus styles
    'focus:outline-none',
    'focus:ring-0',
  ]

  // Auto-resize handling
  if (props.autoResize) {
    classes.push('resize-none')
  } else {
    classes.push('resize-y')
  }

  // Size variants - adjust padding for bordered design
  switch (props.size) {
    case 'sm':
      classes.push('p-3', 'text-sm')
      break
    case 'lg':
      classes.push('p-5', 'text-lg')
      break
    default: // md
      classes.push('p-4', 'text-base')
  }

  // Floating label padding - balanced for readability
  if (hasFloatingLabel.value) {
    switch (props.size) {
      case 'sm':
        classes.push('pt-6')
        break
      case 'lg':
        classes.push('pt-7')
        break
      default: // md
        classes.push('pt-6')
    }
  }

  // State-based styling - update for full border design
  if (hasError.value) {
    classes.push('border-red-500', 'focus:border-red-600')
  } else {
    classes.push(
      'border-current',
      'opacity-30',
      'focus:border-titan-green-800',
      'focus:opacity-100',
      'hover:opacity-50'
    )
  }

  if (props.disabled) {
    classes.push(
      'opacity-50',
      'cursor-not-allowed'
    )
  } else if (props.readonly) {
    classes.push(
      'cursor-default'
    )
  }

  return classes.join(' ')
})

const floatingLabelClasses = computed(() => {
  const classes = [
    'absolute',
    'left-4', // Align with border padding
    'transition-all',
    'duration-200',
    'ease-in-out',
    'origin-left',
    'pointer-events-none',
    'select-none',
    'bg-transparent', // Transparent background to inherit card color
    'px-1', // Small padding for background
  ]

  // Floating state
  const shouldFloat = isFocused.value || hasValue.value || !!props.placeholder

  if (shouldFloat) {
    classes.push(
      'text-xs',
      'font-medium',
      '-top-2',
      'scale-90'
    )

    // Color when floating
    if (hasError.value) {
      classes.push('text-red-600')
    } else if (isFocused.value) {
      classes.push('text-titan-green-800')
    } else {
      classes.push('opacity-70')
    }
  } else {
    classes.push(
      'text-base',
      'font-normal',
      'scale-100',
      'bg-transparent' // No background when not floating
    )

    // Position based on textarea size for bordered design
    switch (props.size) {
      case 'sm':
        classes.push('top-3')
        break
      case 'lg':
        classes.push('top-5')
        break
      default: // md
        classes.push('top-4')
    }

    // Color when not floating
    if (hasError.value) {
      classes.push('text-red-500')
    } else {
      classes.push('opacity-60')
    }
  }

  return classes.join(' ')
})
</script>

<style scoped>
.error-fade-enter-active,
.error-fade-leave-active {
  transition: all 0.2s ease-in-out;
}

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

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