<script setup lang="ts">
import { computed, useSlots, type HTMLAttributes, type Slot } from 'vue'
import { useAttrsWithDefaults } from '../../../composables/useAttrsWithDefaults'
import FdsIcon from '../../FdsIcon/FdsIcon.vue'
import type { FdsSelectProps } from './types'

defineOptions({
  inheritAttrs: false,
})

// Support both v-model (modelValue) and :value prop for backward compatibility
const modelValue = defineModel<string>()

const props = withDefaults(defineProps<FdsSelectProps>(), {
  value: undefined,
  label: undefined,
  meta: undefined,
  optional: false,
  valid: undefined,
  invalidMessage: undefined,
  options: undefined,
  dataTestid: undefined,
  inputClass: undefined,
})

const emit = defineEmits<{
  (e: 'input', ev: Event): void
  (e: 'change', ev: Event): void
  (e: 'update:value', value: string): void
}>()

const { id, placeholder, attrs, disabled } = useAttrsWithDefaults(props)

const autoId = `fds-select-${Math.random().toString(36).slice(2, 9)}`
const selectId = computed(() => (id.value && id.value.trim() !== '' ? id.value : autoId))

const labelAttrs = computed(() => {
  const eventHandlers: Record<string, unknown> = {}
  for (const key in attrs) {
    if (key.startsWith('on') && typeof attrs[key] === 'function') {
      eventHandlers[key] = attrs[key]
    }
  }
  return eventHandlers
})

const selectAttrs = computed(() => {
  const { class: _class, id: _id, ...rest } = attrs
  const filtered: Record<string, unknown> = {}
  for (const key in rest) {
    if (!key.startsWith('on') || typeof rest[key] !== 'function') {
      filtered[key] = rest[key]
    }
  }
  return {
    ...filtered,
    id: selectId.value,
    disabled: disabled.value,
    'aria-invalid': props.valid === false ? ('true' as const) : undefined,
    'data-testid': props.dataTestid ?? undefined,
  } as any
})

const slots = useSlots()
const hasDefaultSlot = computed(() => !!slots.default)

const externalClass = computed(() => attrs.class as HTMLAttributes['class'] | undefined)

const showInvalidMessage = computed(
  () => props.valid === false && !props.optional && props.invalidMessage && !disabled.value,
)
const isInvalid = computed(() => props.valid === false && !props.optional && !disabled.value)

const inputClasses = computed(() => [
  'block w-full rounded-md border border-gray-500 px-3 py-2 pr-10 h-12',
  'focus:outline-2 focus:outline-blue-500 focus:border-transparent',
  'appearance-none',
  disabled.value
    ? 'outline-dashed text-gray-800 outline-2 -outline-offset-2 outline-gray-400 cursor-not-allowed border-transparent'
    : 'bg-white cursor-pointer',
  isInvalid.value && !disabled.value && 'outline-2 -outline-offset-2 outline-red-600 text-red-700',
  props.inputClass,
])

// Use modelValue if bound via v-model, otherwise use value prop
const internalValue = computed({
  get: () => (modelValue.value !== undefined ? modelValue.value : (props.value ?? '')),
  set: (newValue: string) => {
    // Update modelValue if it's being used
    if (modelValue.value !== undefined) {
      modelValue.value = newValue as string
    }
    // Always emit update:value for backward compatibility
    emit('update:value', newValue)
  },
})

function handleChange(ev: Event) {
  emit('change', ev)
  emit('input', ev)
}

defineSlots<{
  default?: Slot
}>()
</script>

<template>
  <div class="w-fit mb-6" :class="externalClass">
    <label
      v-if="label"
      :for="selectId"
      class="block font-bold text-gray-900 cursor-pointer"
      :class="{ 'mb-0': meta, 'mb-1': !meta }"
      v-bind="labelAttrs"
    >
      {{ label }}
    </label>
    <div v-if="meta" class="font-thin mb-1">
      {{ meta }}
    </div>
    <div class="flex relative">
      <select
        v-model="internalValue"
        :class="inputClasses"
        v-bind="selectAttrs"
        @change="handleChange"
        @input="(e) => emit('input', e)"
      >
        <option v-if="placeholder && !hasDefaultSlot" value="" disabled>
          {{ placeholder }}
        </option>
        <!-- Render options from prop if no slot is provided -->
        <template v-if="!hasDefaultSlot && options">
          <option v-for="option in options" :key="option.value" :value="option.value" :disabled="option.disabled">
            {{ option.label }}
          </option>
        </template>
        <!-- Render slot content (supports optgroups and custom options) -->
        <slot v-else />
      </select>
      <div class="absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none">
        <FdsIcon
          name="arrowDown"
          :size="24"
          :class="{
            'fill-gray-500': disabled,
            'fill-red-500': isInvalid && !disabled,
            'fill-blue-500': !disabled && !isInvalid,
          }"
        />
      </div>
    </div>
    <div v-if="showInvalidMessage" class="text-red-700 font-bold mt-1">
      {{ invalidMessage }}
    </div>
  </div>
</template>
