<template>
    <div class="input-container">
        <!-- Label -->
        <label v-if="label" :for="inputId" class="input-label" :class="labelClasses">
            {{ label }}
            <span v-if="required" class="required-indicator" aria-label="required">*</span>
        </label>

        <!-- Input Container -->
        <div class="input-wrapper" :class="wrapperClasses">
            <!-- Prefix Icon -->
            <div v-if="prefixIcon || slots.prefix" class="input-prefix">
                <slot name="prefix">
                    <span v-if="prefixIcon" class="material-icons input-icon">{{ prefixIcon }}</span>
                </slot>
            </div>

            <!-- Input Element -->
            <input :id="inputId" ref="inputRef" v-bind="$attrs" :type="inputType" :value="modelValue"
                :placeholder="placeholder" :disabled="disabled || loading" :readonly="readonly" :required="required"
                :autocomplete="autocomplete" :aria-invalid="hasError ? 'true' : undefined"
                :aria-describedby="descriptionId" class="input-field" :class="inputClasses" @input="handleInput"
                @blur="handleBlur" @focus="handleFocus" @keydown="handleKeydown" />

            <!-- Suffix Content -->
            <div v-if="suffixIcon || loading || hasError || hasSuccess || showPassword || slots.suffix"
                class="input-suffix">
                <!-- Loading Spinner -->
                <div v-if="loading" class="input-loading">
                    <svg class="animate-spin h-4 w-4 text-neutral-400" fill="none" viewBox="0 0 24 24">
                        <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" class="opacity-25">
                        </circle>
                        <path fill="currentColor"
                            d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
                            class="opacity-75"></path>
                    </svg>
                </div>

                <!-- Success Indicator -->
                <div v-else-if="hasSuccess && !hasError" class="input-success">
                    <span class="material-icons input-icon text-success-500">check_circle</span>
                </div>

                <!-- Error Indicator -->
                <div v-else-if="hasError" class="input-error-icon">
                    <span class="material-icons input-icon text-error-500">error</span>
                </div>

                <!-- Password Toggle -->
                <button v-else-if="showPassword" type="button" class="input-password-toggle"
                    @click="togglePasswordVisibility" :aria-label="passwordVisible ? 'Hide password' : 'Show password'">
                    <span class="material-icons input-icon">{{ passwordVisible ? 'visibility_off' : 'visibility'
                        }}</span>
                </button>

                <!-- Suffix Icon or Slot -->
                <div v-else-if="suffixIcon || slots.suffix" class="input-suffix-content">
                    <slot name="suffix">
                        <span v-if="suffixIcon" class="material-icons input-icon">{{ suffixIcon }}</span>
                    </slot>
                </div>
            </div>
        </div>

        <!-- Help Text / Error Message -->
        <div v-if="helpText || error" :id="descriptionId" class="input-description">
            <div v-if="error" class="input-error-text">
                <span class="material-icons input-error-icon-small">error</span>
                {{ error }}
            </div>
            <div v-else-if="helpText" class="input-help-text">
                {{ helpText }}
            </div>
        </div>

        <!-- Character Count -->
        <div v-if="maxLength && showCharCount" class="input-char-count">
            <span :class="characterCountClasses">
                {{ characterCount }}/{{ maxLength }}
            </span>
        </div>
    </div>
</template>

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

interface Props {
    modelValue?: string | number | null
    label?: string
    placeholder?: string
    type?: string
    error?: string | null
    helpText?: string
    disabled?: boolean
    readonly?: boolean
    required?: boolean
    loading?: boolean
    success?: boolean
    prefixIcon?: string
    suffixIcon?: string
    autocomplete?: string
    maxLength?: number
    showCharCount?: boolean
    size?: 'sm' | 'md' | 'lg'
    variant?: 'default' | 'soft' | 'ghost'
    validateOnBlur?: boolean
    validateOnInput?: boolean
    id?: string
}

const props = withDefaults(defineProps<Props>(), {
    type: 'text',
    size: 'md',
    variant: 'default',
    validateOnBlur: true,
    validateOnInput: false,
    showCharCount: false,
})

const emit = defineEmits<{
    'update:modelValue': [value: string | number | null]
    'focus': [event: FocusEvent]
    'blur': [event: FocusEvent]
    'input': [event: Event]
    'keydown': [event: KeyboardEvent]
    'validate': [value: string | number | null]
}>()

// Refs and Slots
const slots = useSlots()
const inputRef = ref<HTMLInputElement | null>(null)
const isFocused = ref(false)
const passwordVisible = ref(false)

// Computed Properties
const inputId = computed(() => props.id || `input-${Math.random().toString(36).substr(2, 9)}`)
const descriptionId = computed(() => `${inputId.value}-description`)
const hasError = computed(() => Boolean(props.error))
const hasSuccess = computed(() => props.success && !hasError.value)
const showPassword = computed(() => props.type === 'password')
const inputType = computed(() => {
    if (props.type === 'password') {
        return passwordVisible.value ? 'text' : 'password'
    }
    return props.type
})

const characterCount = computed(() => {
    if (props.modelValue == null) return 0
    return String(props.modelValue).length
})

const characterCountClasses = computed(() => [
    'text-xs font-mono',
    {
        'text-error-500': props.maxLength && characterCount.value > props.maxLength,
        'text-warning-500': props.maxLength && characterCount.value > props.maxLength * 0.8,
        'text-neutral-500': !props.maxLength || characterCount.value <= props.maxLength * 0.8,
    }
])

// Label Classes
const labelClasses = computed(() => [
    'block text-sm font-medium mb-2 transition-colors duration-micro',
    {
        'text-neutral-700': !hasError.value && !isFocused.value,
        'text-primary-600': isFocused.value && !hasError.value,
        'text-error-600': hasError.value,
        'opacity-50': props.disabled,
    }
])

// Wrapper Classes  
const wrapperClasses = computed(() => [
    'relative flex items-center transition-all duration-micro',
    {
        'opacity-50': props.disabled,
    }
])

// Input Classes
const inputClasses = computed(() => {
    const sizeClasses = {
        sm: 'h-9 text-sm px-3',
        md: 'h-11 text-base px-4',
        lg: 'h-13 text-lg px-5',
    }

    const variantClasses = {
        default: 'bg-white border border-neutral-300',
        soft: 'bg-neutral-50 border border-neutral-200',
        ghost: 'bg-transparent border border-transparent',
    }

    return [
        // Base styles
        'block w-full rounded-lg font-sans transition-all duration-micro ease-micro',
        'placeholder:text-neutral-400 placeholder:font-normal',
        'focus:outline-none focus:ring-2 focus:ring-offset-0',
        // Size classes
        sizeClasses[props.size],
        // Variant classes  
        variantClasses[props.variant],
        // State classes
        {
            // Focus states
            'focus:ring-primary-500/20 focus:border-primary-500': !hasError.value && !props.disabled,
            'focus:ring-error-500/20 focus:border-error-500': hasError.value && !props.disabled,

            // Error states
            'border-error-300 bg-error-50': hasError.value && props.variant === 'default',
            'border-error-200 bg-error-25': hasError.value && props.variant === 'soft',

            // Success states
            'border-success-300 bg-success-50': hasSuccess.value && props.variant === 'default',
            'border-success-200 bg-success-25': hasSuccess.value && props.variant === 'soft',

            // Disabled states
            'cursor-not-allowed bg-neutral-100 text-neutral-500': props.disabled,
            'cursor-default': props.readonly,

            // Loading states
            'pr-10': props.loading || hasError.value || hasSuccess.value || showPassword.value,
            'pl-10': props.prefixIcon || !!slots.prefix,
        }
    ]
})

// Methods
const handleInput = (event: Event) => {
    const target = event.target as HTMLInputElement
    const value = target.value

    emit('update:modelValue', value)
    emit('input', event)

    if (props.validateOnInput) {
        emit('validate', value)
    }
}

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

    if (props.validateOnBlur) {
        emit('validate', props.modelValue ?? null)
    }
}

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

const handleKeydown = (event: KeyboardEvent) => {
    emit('keydown', event)
}

const togglePasswordVisibility = () => {
    passwordVisible.value = !passwordVisible.value
}

const focus = () => {
    nextTick(() => {
        inputRef.value?.focus()
    })
}

const blur = () => {
    inputRef.value?.blur()
}

const select = () => {
    inputRef.value?.select()
}

// Watch for maxLength validation
watch(() => characterCount.value, (newCount) => {
    if (props.maxLength && newCount > props.maxLength) {
        emit('validate', props.modelValue ?? null)
    }
})

// Expose methods
defineExpose({
    focus,
    blur,
    select,
    inputRef,
})
</script>

<style scoped>
.input-container {
    @apply w-full;
}

.input-label {
    user-select: none;
}

.required-indicator {
    @apply text-error-500 ml-1;
}

.input-wrapper {
    @apply relative;
}

.input-field {
    /* Remove default appearance */
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
}

.input-field::-webkit-outer-spin-button,
.input-field::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.input-field[type=number] {
    -moz-appearance: textfield;
}

.input-prefix,
.input-suffix {
    @apply absolute inset-y-0 flex items-center pointer-events-none;
}

.input-prefix {
    @apply left-3;
}

.input-suffix {
    @apply right-3;
}

.input-icon {
    @apply text-lg text-neutral-400;
}

.input-loading {
    @apply pointer-events-none;
}

.input-password-toggle {
    @apply pointer-events-auto p-1 rounded text-neutral-400 hover:text-neutral-600 transition-colors duration-micro;
}

.input-description {
    @apply mt-2;
}

.input-error-text {
    @apply flex items-center gap-1 text-sm text-error-600;
}

.input-error-icon-small {
    @apply text-base;
}

.input-help-text {
    @apply text-sm text-neutral-500;
}

.input-char-count {
    @apply mt-1 text-right;
}

/* Focus ring for accessibility */
.input-field:focus {
    @apply ring-2 ring-offset-0;
}

/* Animation for success/error states */
.input-success,
.input-error-icon {
    animation: scaleIn 150ms ease-out;
}

@keyframes scaleIn {
    0% {
        opacity: 0;
        transform: scale(0.8);
    }

    100% {
        opacity: 1;
        transform: scale(1);
    }
}
</style>