<template>
  <div class="map-search-box" @click.stop>
    <div class="search-input-wrap" :class="{ 'is-open': open && hasResults }">
      <i class="search-icon"></i>
      <input
        ref="input"
        v-model="query"
        :placeholder="placeholder"
        class="search-input"
        @focus="open = true"
        @keydown.down.prevent="moveSelection(1)"
        @keydown.up.prevent="moveSelection(-1)"
        @keydown.enter.prevent="selectActive"
        @keydown.esc="handleEsc"
        @compositionstart="composing = true"
        @compositionend="onCompositionEnd"
      />
      <i v-if="query" class="clear-icon" @click="clear" title="清空">✕</i>
    </div>

    <div v-if="open && query && !composing" class="search-dropdown">
      <div v-if="filtered.length === 0" class="dropdown-empty">无匹配路口</div>
      <div
        v-for="(item, idx) in filtered"
        :key="item[idField]"
        class="dropdown-item"
        :class="{ 'is-active': idx === activeIdx }"
        @mouseenter="activeIdx = idx"
        @mousedown.prevent="selectItem(item)"
      >
        <div class="item-name">{{ item[nameField] }}</div>
        <div class="item-id">{{ item[idField] }}</div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'MapSearchBox',
  props: {
    dataSource: { type: Array, required: true },
    placeholder: { type: String, default: '搜路口' },
    maxResults: { type: Number, default: 10 },
    searchFields: { type: Array, default: () => ['路口名称', '路口编号'] },
    nameField: { type: String, default: '路口名称' },
    idField: { type: String, default: '路口编号' },
  },
  data() {
    return {
      query: '',
      open: false,
      activeIdx: 0,
      composing: false,
    };
  },
  computed: {
    filtered() {
      const q = this.query.trim().toLowerCase();
      if (!q) return [];
      const out = [];
      const fields = this.searchFields;
      for (const item of this.dataSource) {
        for (const f of fields) {
          const v = item[f];
          if (v != null && String(v).toLowerCase().includes(q)) {
            out.push(item);
            break;
          }
        }
        if (out.length >= this.maxResults) break;
      }
      return out;
    },
    hasResults() {
      return this.query && !this.composing;
    },
  },
  watch: {
    filtered() {
      this.activeIdx = 0;
    },
  },
  mounted() {
    this._outsideHandler = (e) => {
      if (!this.$el.contains(e.target)) this.open = false;
    };
    document.addEventListener('click', this._outsideHandler);
  },
  beforeDestroy() {
    if (this._outsideHandler) {
      document.removeEventListener('click', this._outsideHandler);
      this._outsideHandler = null;
    }
  },
  methods: {
    moveSelection(delta) {
      const len = this.filtered.length;
      if (len === 0) return;
      this.activeIdx = (this.activeIdx + delta + len) % len;
    },
    selectActive() {
      const item = this.filtered[this.activeIdx];
      if (item) this.selectItem(item);
    },
    selectItem(item) {
      this.$emit('select', item);
      this.open = false;
      this.query = '';
      this.$refs.input && this.$refs.input.blur();
    },
    handleEsc() {
      if (this.open) {
        this.open = false;
      } else {
        this.clear();
      }
    },
    clear() {
      this.query = '';
      this.activeIdx = 0;
      this.$refs.input && this.$refs.input.focus();
    },
    onCompositionEnd() {
      this.composing = false;
    },
  },
};
</script>

<style scoped>
.map-search-box {
  width: 300px;
  font-family: inherit;
}

.search-input-wrap {
  position: relative;
  display: flex;
  align-items: center;
  height: 38px;
  background: rgba(5, 22, 45, 0.9);
  border: 1px solid #1e4d8e;
  border-radius: 7px;
  backdrop-filter: blur(8px);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
  transition: border-color 0.15s;
}

.search-input-wrap:focus-within,
.search-input-wrap.is-open {
  border-color: #3a7fd1;
}

.search-icon {
  width: 14px;
  height: 14px;
  margin: 0 8px 0 12px;
  border: 1.5px solid rgba(255, 255, 255, 0.5);
  border-radius: 50%;
  position: relative;
  flex-shrink: 0;
}

.search-icon::after {
  content: '';
  position: absolute;
  width: 1.5px;
  height: 6px;
  background: rgba(255, 255, 255, 0.5);
  right: -3px;
  bottom: -3px;
  transform: rotate(-45deg);
}

.search-input {
  flex: 1;
  height: 100%;
  line-height: 38px;
  background: transparent;
  border: none;
  outline: none;
  color: #fff;
  font-size: 13px;
  padding: 0;
  min-width: 0;
}

.search-input::placeholder {
  color: rgba(255, 255, 255, 0.4);
}

.clear-icon {
  width: 18px;
  height: 18px;
  line-height: 18px;
  text-align: center;
  margin: 0 8px;
  color: rgba(255, 255, 255, 0.5);
  cursor: pointer;
  font-size: 12px;
  font-style: normal;
  border-radius: 50%;
  flex-shrink: 0;
  user-select: none;
}

.clear-icon:hover {
  color: #fff;
  background: rgba(255, 255, 255, 0.1);
}

.search-dropdown {
  margin-top: 6px;
  max-height: 320px;
  overflow-y: auto;
  background: rgba(5, 22, 45, 0.92);
  border: 1px solid #1e4d8e;
  border-radius: 7px;
  backdrop-filter: blur(8px);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
}

.dropdown-empty {
  padding: 14px 12px;
  text-align: center;
  color: rgba(255, 255, 255, 0.4);
  font-size: 12px;
}

.dropdown-item {
  padding: 8px 12px;
  cursor: pointer;
  border-bottom: 1px solid rgba(30, 77, 142, 0.25);
  transition: background 0.12s;
}

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

.dropdown-item.is-active,
.dropdown-item:hover {
  background: rgba(30, 77, 142, 0.4);
}

.item-name {
  color: #fff;
  font-size: 13px;
  line-height: 1.4;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.item-id {
  margin-top: 2px;
  color: rgba(120, 200, 255, 0.6);
  font-size: 11px;
  font-family: 'Consolas', monospace;
}

.search-dropdown::-webkit-scrollbar {
  width: 6px;
}

.search-dropdown::-webkit-scrollbar-thumb {
  background: rgba(30, 77, 142, 0.6);
  border-radius: 3px;
}

.search-dropdown::-webkit-scrollbar-track {
  background: transparent;
}
</style>
