<template>
  <div class="autosuggest-container" ref="container">
    <div class="search-wrapper">
      <PhMagnifyingGlass :size="32" weight="bold" class="search-icon"/>
      <input
          ref="searchInput"
          v-model="searchQuery"
          @input="onInput"
          @keydown="onKeyDown"
          @focus="onFocus"
          @blur="onBlur"
          type="text"
          class="search-input"
          :placeholder="placeholder"
          autocomplete="off"
      />
      <div v-if="isLoading" class="loading-indicator">
        <spinner size="s"></spinner>
      </div>
    </div>


    <transition name="dropdown">
      <div
          v-if="showSuggestions && suggestions.length > 0"
          class="suggestions-dropdown"
      >
        <ul class="suggestions-list">
          <li
              v-for="(suggestion, index) in suggestions"
              :key="getIdFor(suggestion, index)"
              @click="selectItem(suggestion)"
              @mouseenter="highlightedIndex = index"
              :class="[
            'suggestion-item',
            { 'highlighted': index === highlightedIndex }
          ]"
          >
            <div v-if="isFlagVariant">
              <div class="suggestion-content-with-flag">
                <flag :iso="getFlagIsoFor(suggestion)"></flag>
                <div>
                  <div class="suggestion-title">{{ getTitleFor(suggestion) }}</div>
                  <div v-if="getSubtitleFor(suggestion)" class="suggestion-subtitle">
                    {{ getSubtitleFor(suggestion) }}
                  </div>
                </div>
              </div>
            </div>
            <div v-else>
              <div class="suggestion-content">
                <div class="suggestion-title">{{ getTitleFor(suggestion) }}</div>
                <basic-badge variant="grey" v-if="getSubtitleFor(suggestion)">{{
                    getSubtitleFor(suggestion)
                  }}
                </basic-badge>
              </div>
            </div>
          </li>
        </ul>
      </div>
    </transition>


    <div
        v-if="showSuggestions && searchQuery && suggestions.length === 0 && !isLoading && !allowFreeInput"
        class="no-results"
    >
      {{ noResultsText.replace('{query}', searchQuery) }}
    </div>
  </div>
</template>

<script>
import Spinner from "@/components/UI/Spinner.vue";
import Flag from "@/components/UI/Flag.vue";
import {useDebounceFn} from "@vueuse/core";
import BasicBadge from "@/components/UI/BasicBadge.vue";
import logger from "@/logger.js";

export default {
  name: 'AutosuggestSearchbar',
  components: {BasicBadge, Flag, Spinner},
  emits: ['selected', 'search', 'suggestions-loaded', 'error'],
  props: {
    // Display props
    placeholder: {
      type: String,
      default: 'Search...'
    },
    noResultsText: {
      type: String,
      default: 'No results found for "{query}"'
    },
    variant: {
      type: String,
      default: "tags"
    },
    // Behavior props
    minChars: {
      type: Number,
      default: 2
    },
    fetchSuggestions: {
      type: Function,
      required: true
      // Expected signature: async (query: string) => Array
    },
    titleResolver: {
      type: [String, Function],
      default: 'title'
    },
    subtitleResolver: {
      type: [String, Function],
      default: 'subtitle'
    },
    idResolver: {
      type: [String, Function],
      default: 'id'
    },
    flagResolver: {
      type: [String, Function],
      default: 'iso'
    },
    resetOnSelect: {
      type: Boolean,
      default: false
    },
    initialSuggestions: {
      type: Array,
      default: () => []
    },
    initialValue: {
      type: String,
      default: '',
    },
    activateWatcher: {
      type: Boolean,
      default: false,
    },
    allowFreeInput: {
      type: Boolean,
      default: false
    }
  },

  data() {
    return {
      searchQuery: '',
      suggestions: [...this.initialSuggestions],
      isLoading: false,
      showSuggestions: false,
      highlightedIndex: -1,
      debounceTimer: null,
      debouncedSearch: null,
    }
  },
  computed: {
    isFlagVariant() {
      return this.variant === 'flags';
    }
  },
  methods: {
    onInput() {
      this.debouncedSearch(this.searchQuery);
    },

    async handleSearch() {
      const query = this.searchQuery.trim()

      if (query.length < this.minChars) {
        this.hideSuggestions()
        this.suggestions = []
        return
      }

      this.isLoading = true

      try {
        const results = await this.fetchSuggestions(query)
        this.suggestions = Array.isArray(results) ? results : []
        this.showSuggestions = true
        this.highlightedIndex = -1
        this.$emit('suggestions-loaded', this.suggestions)
      } catch (error) {
        logger.error('Error fetching suggestions:', error)
        this.suggestions = []
        this.hideSuggestions()
        this.$emit('error', error)
      } finally {
        this.isLoading = false
      }
    },

    onFocus() {
      if (this.searchQuery.length >= this.minChars && this.suggestions.length > 0) {
        this.showSuggestions = true
      }
    },

    onBlur() {
      // Verzögerung, damit Click-Event auf Suggestion noch registriert wird
      setTimeout(() => {
        if (this.allowFreeInput && this.searchQuery.trim()) {
          // Emit search event mit freiem Text
          this.$emit('search', this.searchQuery)
        }
      }, 200)
    },

    onKeyDown(event) {
      if (!this.showSuggestions || this.suggestions.length === 0) {
        // Wenn allowFreeInput aktiviert ist, erlaube Enter auch ohne Vorschläge
        if (event.key === 'Enter' && this.allowFreeInput) {
          event.preventDefault()
          this.handleEnterWithoutSelection()
        }
        return
      }

      switch (event.key) {
        case 'ArrowDown':
          event.preventDefault()
          this.highlightedIndex = Math.min(
              this.highlightedIndex + 1,
              this.suggestions.length - 1
          )
          break

        case 'ArrowUp':
          event.preventDefault()
          this.highlightedIndex = Math.max(this.highlightedIndex - 1, -1)
          break

        case 'Enter':
          event.preventDefault()
          if (this.highlightedIndex >= 0) {
            this.selectItem(this.suggestions[this.highlightedIndex])
          } else {
            this.handleEnterWithoutSelection()
          }
          break

        case 'Escape':
          this.hideSuggestions()
          this.$refs.searchInput.blur()
          break

        case 'Tab':
          this.hideSuggestions()
          break
      }
    },

    selectItem(suggestion) {
      if (this.resetOnSelect) {
        this.searchQuery = '';
      } else {
        this.searchQuery = this.getTitleFor(suggestion)
      }
      this.hideSuggestions()
      this.$emit('selected', suggestion)
      this.$emit('search', this.searchQuery)
      this.$refs.searchInput.blur()
    },

    handleEnterWithoutSelection() {
      const query = this.searchQuery.trim()

      // Wenn allowFreeInput deaktiviert ist und keine Vorschläge vorhanden sind, nichts tun
      if (!this.allowFreeInput && this.suggestions.length === 0) {
        return
      }

      this.hideSuggestions()

      if (query) {
        this.$emit('search', query)
      }
    },

    hideSuggestions() {
      this.showSuggestions = false
      this.highlightedIndex = -1
    },

    // Helper methods for extracting data from suggestion objects
    getTitleFor(suggestion) {
      if (typeof this.titleResolver === 'function') {
        return this.titleResolver(suggestion)
      }
      return suggestion[this.titleResolver] || suggestion.toString()
    },

    getSubtitleFor(suggestion) {
      if (typeof this.subtitleResolver === 'function') {
        return this.subtitleResolver(suggestion)
      }
      return suggestion[this.subtitleResolver] || null
    },
    getFlagIsoFor(suggestion) {
      if (typeof this.flagResolver === 'function') {
        return this.flagResolver(suggestion)
      }
      return suggestion[this.flagResolver] || null
    },

    getIdFor(suggestion, index) {
      if (typeof this.idResolver === 'function') {
        return this.idResolver(suggestion)
      }
      return suggestion[this.idResolver] || index
    },

    handleClickOutside(event) {
      if (!this.$refs.container.contains(event.target)) {
        this.hideSuggestions()
      }
    },

    // Public methods for external control
    clearSuggestions() {
      this.suggestions = []
      this.hideSuggestions()
    },

    focus() {
      this.$refs.searchInput.focus()
    },

    blur() {
      this.$refs.searchInput.blur()
      this.hideSuggestions()
    },

    setQuery(query) {
      this.searchQuery = query;
    }
  },

  created() {
    this.debouncedSearch = useDebounceFn((query) => {
      this.handleSearch(query);
    }, 300);
  },

  mounted() {
    this.searchQuery = this.initialValue;
    document.addEventListener('click', this.handleClickOutside)
  },

  beforeUnmount() {
    document.removeEventListener('click', this.handleClickOutside)
    if (this.debounceTimer) {
      clearTimeout(this.debounceTimer)
    }
  },

  watch: {
    suggestions() {
      // Reset highlighted index when suggestions change
      this.highlightedIndex = -1
    },
    initialSuggestions: {
      handler(newSuggestions) {
        this.suggestions = [...newSuggestions]
      },
      immediate: true
    },
    initialValue(newValue) {
      if (this.activateWatcher)
        this.setQuery(newValue);
    }
  }
}
</script>

<style scoped>
.autosuggest-container {
  position: relative;
}

.search-wrapper {
  display: flex;
  align-items: center;
  background: white;
  border-radius: 0.4rem;
  padding: 0.6rem 1.2rem;
  /* box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);*/
  border: 0.2rem solid #E3EDFF;
  transition: all 0.1s ease;

}

.search-wrapper:hover {
  background: #EEF4FF;
  border: 0.2rem solid #8DB3FE;
  /*transform: translateY(2px);*/
  transform: scale(1.01);
}


.search-input {
  border: none;
  outline: none;
  background: none;
  resize: none;
  width: 100%;
  font-size: 1.4rem;
  font-family: inherit;
  color: #002F54;
  font-weight: 400;
  min-width: 10rem;
}

.search-icon {
  width: 1.8rem;
  height: 1.8rem;
  margin-right: 1.2rem;
  color: #6B869C;
  flex-shrink: 0;
}

.search-input::placeholder {
  color: #6B869C;
  font-weight: 400;
}

.loading-indicator {
  position: absolute;
  right: 1.6rem;
  pointer-events: none;
}

.dropdown-enter-active {
  transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

.dropdown-leave-active {
  transition: all 0.2s ease-in;
}

.dropdown-enter-from {
  transform: translateY(-30px);
  opacity: 0;
}

.dropdown-leave-to {
  transform: translateY(-30px);
  opacity: 0;
}

.suggestions-dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  background: white;
  border: 0.1rem solid #E3EDFF;
  border-radius: 0.8rem;
  box-shadow: 0 0.4rem 0.6rem -0.1rem rgba(0, 0, 0, 0.1);
  backdrop-filter: blur(10px);
  z-index: 1;
  max-height: 40rem;
  overflow-y: auto;
  margin-top: 0.4rem;

}

.suggestions-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.suggestion-item {
  padding: 1.2rem 1.6rem;
  cursor: pointer;
  border-bottom: 0.16rem solid #f3f4f6;
  transition: background-color 0.2s ease;
}

.suggestion-item:last-child {
  border-bottom: none;
}

.suggestion-item:hover,
.suggestion-item.highlighted {
  background-color: rgba(107, 134, 156, 0.05);
}

.suggestion-content-with-flag {
  display: flex;
  flex-direction: row;
  justify-content: flex-start;
  align-items: center;
  gap: 1.6rem;
}

.suggestion-content {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  flex-direction: column;
}

.suggestion-title {
  flex: 1;
  font-size: 1.6rem;
  color: #001D33;
}

.suggestion-subtitle {
  font-size: 1.4rem;
  color: #6b7280;
}

.suggestion-subtitle-tag {
  font-size: 1.4rem;
  color: #ffffff;
  background-color: #003c6a;
  padding: 0.4rem 0.8rem;
  border-radius: 0.4rem;
}

.no-results {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  padding: 1.6rem;
  text-align: center;
  color: #001D33;
  border: 0.1rem solid #e0e0e0;
  border-radius: 0.8rem;
  margin-top: 0.4rem;
  background: white;
  font-size: 1.6rem;
  z-index: 1;
}

/* Mobile responsiveness */
@media (max-width: 768px) {
  .search-input {
    font-size: 16px; /* Prevents zoom on iOS */
  }

  .suggestions-dropdown {
    max-height: 200px;
  }
}
</style>