<!-- base/BaseSelect.vue -->
<template>
  <div class="select-wrapper">
    <label v-if="label" :for="id" class="select-label">
      {{ label }}
      <span v-if="required" class="required-mark">*</span>
    </label>

    <!-- Custom dropdown mode (when deletableOptions provided) -->
    <div
      v-if="deletableOptions !== null"
      class="custom-select"
      :class="{ 'has-error': error, 'is-open': isOpen, 'is-disabled': disabled }"
      ref="selectRef"
    >
      <button
        type="button"
        class="custom-select-trigger"
        :id="id"
        :disabled="disabled"
        @click="toggleDropdown"
        @keydown="handleTriggerKeydown"
        role="combobox"
        :aria-expanded="isOpen"
        aria-haspopup="listbox"
        :aria-controls="`${id}-listbox`"
      >
        <span :class="{ 'placeholder-text': !modelValue }">
          {{ displayLabel }}
        </span>
        <svg class="select-arrow" :class="{ 'arrow-up': isOpen }" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
          <path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z" clip-rule="evenodd" />
        </svg>
      </button>

      <div
        v-show="isOpen"
        :id="`${id}-listbox`"
        class="custom-select-dropdown"
      >
        <ul
          class="custom-select-list"
          role="listbox"
          @keydown="handleListKeydown"
        >
          <li
            v-for="(option, index) in options"
            :key="option.value"
            class="custom-select-option"
            :class="{
              'is-selected': option.value === modelValue,
              'is-highlighted': index === highlightedIndex,
              'is-deletable': isDeletable(option.value)
            }"
            role="option"
            :aria-selected="option.value === modelValue"
            @click.stop="selectOption(option.value)"
            @mouseenter="highlightedIndex = index"
          >
            <span class="option-label">{{ option.label }}</span>
            <button
              v-if="isDeletable(option.value)"
              type="button"
              class="option-delete-btn"
              @click.stop="handleDeleteOption(option.value)"
              :title="deleteTitle || 'Delete custom option'"
              tabindex="-1"
            >&#x2715;</button>
          </li>
        </ul>

        <!-- Inline custom input at the bottom of the dropdown -->
        <div v-if="allowCustomInput" class="custom-input-row">
          <input
            ref="customInputRef"
            v-model.trim="customInputValue"
            type="text"
            class="custom-input-field"
            :placeholder="customInputPlaceholder || 'Type custom value...'"
            :maxlength="255"
            @keydown.enter.prevent="submitCustomValue"
            @keydown.escape.prevent="isOpen = false"
            @click.stop
          />
          <button
            type="button"
            class="custom-input-add-btn"
            :disabled="!customInputValue"
            @click.stop="submitCustomValue"
            tabindex="-1"
          >+</button>
        </div>
      </div>
    </div>

    <!-- Native select mode (default) -->
    <select
      v-else
      :id="id"
      :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)"
      :disabled="disabled"
      :required="required"
      class="base-select"
      :class="{ 'has-error': error }"
    >
      <option value="" disabled selected>{{ placeholder || 'Select option' }}</option>
      <option
        v-for="option in options"
        :key="option.value"
        :value="option.value"
      >
        {{ option.label }}
      </option>
    </select>

    <p v-if="error" class="error-message">{{ error }}</p>
    <p v-if="helpText" class="help-text">{{ helpText }}</p>
  </div>
</template>

<script setup>
import { ref, computed, onMounted, onBeforeUnmount, nextTick, watch } from 'vue';

const props = defineProps({
  id: {
    type: String,
    required: true
  },
  modelValue: {
    type: [String, Number],
    default: ''
  },
  label: {
    type: String,
    default: ''
  },
  placeholder: {
    type: String,
    default: ''
  },
  options: {
    type: Array,
    required: true,
    validator: (options) => {
      return options.every(option =>
        Object.prototype.hasOwnProperty.call(option, 'value') &&
        Object.prototype.hasOwnProperty.call(option, 'label')
      );
    }
  },
  required: {
    type: Boolean,
    default: false
  },
  disabled: {
    type: Boolean,
    default: false
  },
  error: {
    type: String,
    default: ''
  },
  helpText: {
    type: String,
    default: ''
  },
  /**
   * Array of option values that can be deleted.
   * When provided, switches to custom dropdown mode.
   * @since 1.1.1
   */
  deletableOptions: {
    type: Array,
    default: null
  },
  /**
   * Title/tooltip for the delete button
   * @since 1.1.1
   */
  deleteTitle: {
    type: String,
    default: ''
  },
  /**
   * Enable inline custom input at the bottom of the dropdown.
   * @since 1.1.1
   */
  allowCustomInput: {
    type: Boolean,
    default: false
  },
  /**
   * Placeholder for the custom input field
   * @since 1.1.1
   */
  customInputPlaceholder: {
    type: String,
    default: ''
  }
});

const emit = defineEmits(['update:modelValue', 'delete-option', 'add-option']);

// Custom dropdown state
const isOpen = ref(false);
const highlightedIndex = ref(-1);
const selectRef = ref(null);
const customInputRef = ref(null);
const customInputValue = ref('');

/**
 * Display label for the trigger button
 */
const displayLabel = computed(() => {
  if (!props.modelValue) {
    return props.placeholder || 'Select option';
  }
  const found = props.options.find(o => o.value === props.modelValue);
  return found ? found.label : props.modelValue;
});

/**
 * Check if an option value is deletable
 */
const isDeletable = (value) => {
  return props.deletableOptions && props.deletableOptions.includes(value);
};

/**
 * Toggle dropdown open/close
 */
const toggleDropdown = () => {
  if (props.disabled) return;
  isOpen.value = !isOpen.value;
  if (isOpen.value) {
    // Highlight currently selected option
    const idx = props.options.findIndex(o => o.value === props.modelValue);
    highlightedIndex.value = idx >= 0 ? idx : 0;
  }
};

/**
 * Select an option and close dropdown
 */
const selectOption = (value) => {
  emit('update:modelValue', value);
  isOpen.value = false;
};

/**
 * Handle delete button click on an option
 */
const handleDeleteOption = (value) => {
  emit('delete-option', value);
};

/**
 * Submit the custom input value — adds to options and selects it
 */
const submitCustomValue = () => {
  // Sanitize: strip HTML tags, trim, and lowercase
  const val = customInputValue.value.replace(/<[^>]*>/g, "").trim().toLowerCase();
  if (!val) return;

  // Check if this value already exists in options
  const exists = props.options.some(o => o.value === val);
  if (exists) {
    // Just select it
    emit('update:modelValue', val);
  } else {
    // Emit add-option, then select it
    emit('add-option', val);
    emit('update:modelValue', val);
  }

  customInputValue.value = '';
  isOpen.value = false;
};

/**
 * Handle keydown on trigger button
 */
const handleTriggerKeydown = (e) => {
  if (e.key === 'Enter' || e.key === ' ' || e.key === 'ArrowDown') {
    e.preventDefault();
    if (!isOpen.value) {
      isOpen.value = true;
      const idx = props.options.findIndex(o => o.value === props.modelValue);
      highlightedIndex.value = idx >= 0 ? idx : 0;
    }
  } else if (e.key === 'Escape') {
    isOpen.value = false;
  }
};

/**
 * Handle keydown on the dropdown list
 */
const handleListKeydown = (e) => {
  if (e.key === 'ArrowDown') {
    e.preventDefault();
    highlightedIndex.value = Math.min(highlightedIndex.value + 1, props.options.length - 1);
  } else if (e.key === 'ArrowUp') {
    e.preventDefault();
    highlightedIndex.value = Math.max(highlightedIndex.value - 1, 0);
  } else if (e.key === 'Enter') {
    e.preventDefault();
    if (highlightedIndex.value >= 0 && highlightedIndex.value < props.options.length) {
      selectOption(props.options[highlightedIndex.value].value);
    }
  } else if (e.key === 'Escape') {
    isOpen.value = false;
  }
};

/**
 * Close dropdown on click outside
 */
const handleClickOutside = (e) => {
  if (selectRef.value && !selectRef.value.contains(e.target)) {
    isOpen.value = false;
  }
};

/**
 * Auto-focus the custom input when dropdown opens
 */
watch(isOpen, async (open) => {
  if (!open) {
    customInputValue.value = '';
  }
});

onMounted(() => {
  document.addEventListener('click', handleClickOutside);
});

onBeforeUnmount(() => {
  document.removeEventListener('click', handleClickOutside);
});
</script>

<style scoped>
.select-wrapper {
  display: flex;
  flex-direction: column;
}

.select-label {
  font-size: 0.9rem;
  margin-bottom: 0.5rem;
}

.base-select {
  padding: 0.5rem;
  border: 1px solid var(--color-border);
  border-radius: 0.375rem;
}

/* Custom dropdown styles */
.custom-select {
  position: relative;
}

.custom-select-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 0.5rem;
  border: 1px solid var(--color-border, #d1d5db);
  border-radius: 0.375rem;
  background: #fff;
  font-size: inherit;
  font-family: inherit;
  cursor: pointer;
  text-align: left;
  gap: 0.5rem;
}

.custom-select-trigger:hover {
  border-color: #9ca3af;
}

.custom-select.is-open .custom-select-trigger {
  border-color: #6366f1;
  box-shadow: 0 0 0 1px #6366f1;
}

.custom-select.is-disabled .custom-select-trigger {
  background: #f3f4f6;
  cursor: not-allowed;
  opacity: 0.6;
}

.custom-select.has-error .custom-select-trigger {
  border-color: #ef4444;
}

.placeholder-text {
  color: #9ca3af;
}

.select-arrow {
  width: 1.25rem;
  height: 1.25rem;
  color: #6b7280;
  transition: transform 0.15s;
  flex-shrink: 0;
}

.select-arrow.arrow-up {
  transform: rotate(180deg);
}

.custom-select-dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  margin-top: 2px;
  background: #fff;
  border: 1px solid #d1d5db;
  border-radius: 0.375rem;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  z-index: 50;
  overflow: hidden;
}

.custom-select-list {
  max-height: 200px;
  overflow-y: auto;
  padding: 0;
  margin: 0;
  list-style: none;
}

.custom-select-option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.5rem 0.75rem;
  cursor: pointer;
  font-size: 0.875rem;
  gap: 0.5rem;
}

.custom-select-option:hover,
.custom-select-option.is-highlighted {
  background: #f3f4f6;
}

.custom-select-option.is-selected {
  background: #eef2ff;
  font-weight: 500;
}

.custom-select-option.is-deletable {
  padding-right: 0.5rem;
}

.option-label {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.option-delete-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  border: none;
  background: transparent;
  color: #9ca3af;
  font-size: 0.625rem;
  cursor: pointer;
  border-radius: 50%;
  flex-shrink: 0;
  transition: all 0.15s;
  padding: 0;
}

.option-delete-btn:hover {
  background: #fee2e2;
  color: #ef4444;
}

/* Inline custom input at bottom of dropdown */
.custom-input-row {
  display: flex;
  align-items: center;
  gap: 0;
  border-top: 1px solid #e5e7eb;
  padding: 0.375rem;
}

.custom-input-field {
  flex: 1;
  border: 1px solid #d1d5db;
  border-right: none;
  border-radius: 0.25rem 0 0 0.25rem;
  padding: 0.375rem 0.5rem;
  font-size: 0.8125rem;
  font-family: inherit;
  outline: none;
  min-width: 0;
}

.custom-input-field:focus {
  border-color: #6366f1;
  box-shadow: 0 0 0 1px #6366f1;
  position: relative;
  z-index: 1;
}

.custom-input-field::placeholder {
  color: #9ca3af;
  font-size: 0.8125rem;
}

.custom-input-add-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: calc(0.375rem * 2 + 1em + 2px);
  border: 1px solid #6366f1;
  border-radius: 0 0.25rem 0.25rem 0;
  background: #6366f1;
  color: #fff;
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 0.15s;
}

.custom-input-add-btn:hover:not(:disabled) {
  background: #4f46e5;
}

.custom-input-add-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
</style>
