<template>
  <div ref="root" class="metro-line-select">
    <button class="select-trigger" type="button" aria-haspopup="listbox" :aria-expanded="open" @click="open = !open"
      @keydown.down.prevent="moveSelection(1)" @keydown.up.prevent="moveSelection(-1)" @keydown.esc="open = false">
      <span class="selected-line" :style="lineStyle(selectedLine)">
        <strong v-if="isNumberedLine(selectedLine)">{{ selectedLine.id }}</strong>
        <span>{{ isNumberedLine(selectedLine) ? '号线' : selectedLine.name }}</span>
      </span>
      <img class="arrow" :class="{ open }" src="/imgs/driving/arrow.png" alt="" aria-hidden="true" />
    </button>

    <Transition name="line-options">
      <ul v-if="open" class="options" role="listbox">
        <li v-for="line in lineOptions" :key="line.id" :class="{ active: line.id === modelValue }" role="option"
          :aria-selected="line.id === modelValue" @click="selectLine(line.id)">
          <span class="line-swatch" :style="lineStyle(line)">{{ line.name }}</span>
        </li>
      </ul>
    </Transition>
  </div>
</template>

<script setup>
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
import { METRO_LINES } from '@/utils/const.js'

const props = defineProps({
  modelValue: { type: Number, default: 7 }
})
const emit = defineEmits(['update:modelValue', 'change'])

const root = ref(null)
const open = ref(false)
const lineOptions = Object.entries(METRO_LINES).map(([id, theme]) => ({
  id: Number(id),
  ...theme
}))
const selectedLine = computed(() => (
  lineOptions.find(line => line.id === props.modelValue) || lineOptions[0]
))

const lineStyle = line => ({ backgroundColor: line.bg, color: line.color })
const isNumberedLine = line => line.id >= 1 && line.id <= 18

const selectLine = id => {
  emit('update:modelValue', id)
  emit('change', id)
  open.value = false
}

const moveSelection = offset => {
  open.value = true
  const currentIndex = lineOptions.findIndex(line => line.id === props.modelValue)
  const nextIndex = (currentIndex + offset + lineOptions.length) % lineOptions.length
  selectLine(lineOptions[nextIndex].id)
}

const closeOnOutsideClick = event => {
  if (!root.value?.contains(event.target)) open.value = false
}

onMounted(() => document.addEventListener('pointerdown', closeOnOutsideClick))
onBeforeUnmount(() => document.removeEventListener('pointerdown', closeOnOutsideClick))
</script>

<style lang="scss" scoped>
  .metro-line-select {
    position: relative;
    width: 154px;
  }

  .select-trigger {
    display: flex;
    align-items: center;
    width: 100%;
    height: 43px;
    padding: 0 13px 0 18px;
    border: 0;
    border-radius: 4px;
    background: linear-gradient(90deg, rgba(51, 99, 164, .9), rgba(9, 38, 92, .66));
    cursor: pointer;
  }

  .selected-line {
    display: inline-flex;
    // align-items: center;
    justify-content: center;
    gap: 4px;
    min-width: 78px;
    height: 33px;
    padding: 0 9px;
    border-radius: 6px;
    font-size: 13px;
line-height: 1.6;
    white-space: nowrap;

    strong {
      font-size: 30px;
      line-height: 1;
    }
  }

  .arrow {
    width: 16px;
    height: 16px;
    margin-left: 12px;
    object-fit: contain;
    transition: transform .18s ease;

    &.open {
      transform: rotate(180deg);
    }
  }

  .options {
    position: absolute;
    top: 47px;
    right: 0;
    z-index: 20;
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 6px;
    width: 238px;
    max-height: 330px;
    margin: 0;
    padding: 9px;
    overflow-y: auto;
    border: 1px solid rgba(47, 156, 255, .7);
    border-radius: 4px;
    list-style: none;
    background: rgba(3, 24, 68, .98);
    box-shadow: 0 8px 24px rgba(0, 8, 30, .55);
  }

  .options li {
    padding: 2px;
    border: 1px solid transparent;
    border-radius: 3px;
    cursor: pointer;

    &:hover,
    &.active {
      border-color: #60d9ff;
    }
  }

  .line-swatch {
    display: block;
    height: 30px;
    border-radius: 3px;
    font-size: 14px;
    line-height: 30px;
    text-align: center;
    white-space: nowrap;
  }

  .line-options-enter-active,
  .line-options-leave-active {
    transition: opacity .15s ease, transform .15s ease;
  }

  .line-options-enter-from,
  .line-options-leave-to {
    opacity: 0;
    transform: translateY(-5px);
  }
</style>
