<template>
  <div
    ref="switcherRef"
    class="base-map-switcher"
    :class="{ 'is-open': panelVisible }"
  >
    <transition name="base-map-panel">
      <section
        v-if="panelVisible"
        :id="panelId"
        class="base-map-switcher__panel"
        role="dialog"
        aria-modal="false"
        aria-label="底图切换"
        @click.stop
      >
        <el-scrollbar class="base-map-switcher__scroll">
          <ul v-if="baseMapGroups.length" class="base-map-switcher__group-list">
            <li
              v-for="group in baseMapGroups"
              :key="group.id"
            >
              <button
                type="button"
                class="base-map-switcher__group"
                :class="{ 'is-active': group.id === activeGroupId }"
                @click="selectBaseGroup(group)"
              >
                <div class="base-map-switcher__thumb">
                  <MapIcon
                    icon-class="GisLandcoverMap"
                    class="base-map-switcher__icon"
                  />
                  <div
                    v-if="group.id === activeGroupId"
                    class="base-map-switcher__check"
                  ></div>
                </div>
                <div class="base-map-switcher__meta">
                  <span class="base-map-switcher__name">{{ group.name }}</span>
                  <span class="base-map-switcher__count">{{ group.layerIds.length }} 个图层</span>
                </div>
              </button>
            </li>
          </ul>
          <el-empty v-else description="暂无底图" />
        </el-scrollbar>
      </section>
    </transition>
    <button
      class="base-map-switcher__trigger"
       
      type="button"
      :aria-expanded="panelVisible"
      :aria-controls="panelId"
      @click.stop="togglePanel"
    >
      <MapIcon icon-class="GisLandcoverMap" class="base-map-switcher__trigger-icon" />
    </button>
  </div>
</template>

<script setup>
import { computed, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue'
import { storeToRefs } from 'pinia'
import { ElMessage } from 'element-plus'
import MapIcon from '@/map/shared/SvgIcon/index.vue'
import useMapStore from '@/map/stores/mapStore'

const panelId = 'base-map-switcher-panel'

const mapStore = useMapStore()
const { layers: layerTable } = storeToRefs(mapStore)

const switcherRef = ref(null)
const panelVisible = ref(false)
const layerService = shallowRef(null)
let detachReadyListener = null

const baseMapGroups = computed(() => {
  const grouped = new Map()
  const records = Object.values(layerTable.value || {})
    .filter((record) => record && record.meta?.isBaseMap)
  records.forEach((record) => {
    const meta = record.meta || {}
    const groupId = meta.baseGroupId || 'default'
    if (!grouped.has(groupId)) {
      grouped.set(groupId, {
        id: groupId,
        name: meta.baseGroupName || '底图',
        thumbnail: meta.baseGroupThumbnail || '',
        sortValue: normalizeNumber(meta.baseGroupSortValue),
        layerIds: [],
        layers: [],
      })
    }
    const group = grouped.get(groupId)
    group.layerIds.push(record.id)
    group.layers.push(record)
  })
  const list = Array.from(grouped.values())
  list.forEach((group) => {
    group.isActive = group.layers.some((layer) => layer.show)
  })
  return list.sort((a, b) => a.sortValue - b.sortValue)
})

const activeGroupId = computed(() => {
  const activeGroup = baseMapGroups.value.find((group) => group.isActive)
  return activeGroup ? activeGroup.id : (baseMapGroups.value[0]?.id ?? null)
})

function togglePanel() {
  panelVisible.value = !panelVisible.value
}

function resolveLayerService() {
  try {
    layerService.value = mapStore.services().layer
  } catch (err) {
    layerService.value = null
  }
}

function handleOutsideClick(event) {
  if (!panelVisible.value) return
  const el = switcherRef.value
  if (!el) return
  if (!el.contains(event.target)) {
    panelVisible.value = false
  }
}

onMounted(() => {
  resolveLayerService()
  document.addEventListener('click', handleOutsideClick)
  detachReadyListener = mapStore.onReady(() => {
    resolveLayerService()
  })
})

onBeforeUnmount(() => {
  document.removeEventListener('click', handleOutsideClick)
  if (typeof detachReadyListener === 'function') {
    detachReadyListener()
  }
})

watch(
  () => mapStore.ready,
  (ready) => {
    if (ready) resolveLayerService()
    else layerService.value = null
  }
)

function normalizeNumber(input) {
  if (typeof input === 'number' && Number.isFinite(input)) return input
  const num = Number(input)
  return Number.isFinite(num) ? num : 0
}

function createThumbStyle(group) {
  if (group.thumbnail) {
    return {
      backgroundImage: `url(${group.thumbnail})`,
    }
  }
  const key = String(group.id ?? '')
  const seed = Math.abs(key.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0) || 1)
  const hue = (seed * 37) % 360
  return {
    backgroundImage: `linear-gradient(135deg, hsl(${hue}, 68%, 68%), hsl(${(hue + 32) % 360}, 64%, 58%))`,
  }
}

function selectBaseGroup(group) {
  if (!group || !layerService.value) {
    ElMessage.warning('地图尚未就绪')
    return
  }
  try {
    baseMapGroups.value.forEach((candidate) => {
      const visible = candidate.id === group.id
      candidate.layerIds.forEach((layerId) => {
        layerService.value.showLayer(layerId, visible)
      })
    })
    panelVisible.value = false
  } catch (err) {
    console.error('底图切换失败', err)
    ElMessage.error('底图切换失败')
  }
}
</script>

<style scoped lang="scss">
.base-map-switcher {
  position: relative;
  display: flex;
  align-items: flex-end;
  gap: 12px;
  pointer-events: auto;
}

.base-map-switcher.is-open .base-map-switcher__trigger {
  background: #ffffff;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.base-map-switcher__trigger {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: none;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.92);
  color: #1f1f1f;
  font-size: 18px;
  font-weight: 600;
  cursor: pointer;
  transition: background-color 0.2s ease, transform 0.2s ease;
}

.base-map-switcher__trigger:hover {
  background: #ffffff;
  transform: translateY(-1px);
}

.base-map-switcher__trigger:focus-visible {
  outline: 2px solid rgba(79, 233, 255, 0.6);
  outline-offset: 2px;
}

.base-map-switcher__trigger-icon {
  width: 28px;
  height: 28px;
  color: inherit;
}

.base-map-switcher__panel {
  position: absolute;
  right: calc(100% + 12px);
  bottom: 0;
  width: 150px;
  max-height: 240px;
  padding: 12px;
  border-radius: 8px;
  background: rgba(33, 33, 33, 0.45);
  backdrop-filter: blur(10px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  color: #ffffff;
  pointer-events: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.base-map-switcher__scroll {
  max-height: 240px;
}

.base-map-switcher__group-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.base-map-switcher__group {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 6px 8px;
  border-radius: 6px;
  border: 1px solid transparent;
  background: rgba(255, 255, 255, 0.08);
  color: inherit;
  cursor: pointer;
  transition: all 0.2s ease;
}

.base-map-switcher__group:hover {
  background: rgba(255, 255, 255, 0.12);
  transform: translateY(-1px);
}

.base-map-switcher__group.is-active {
  background: rgba(255, 255, 255, 0.92);
  color: #1f1f1f;
}

.base-map-switcher__group.is-active .base-map-switcher__count {
  color: rgba(31, 31, 31, 0.6);
}

.base-map-switcher__group.is-active .base-map-switcher__thumb {
  background: rgba(31, 31, 31, 0.1);
}

.base-map-switcher__group.is-active .base-map-switcher__icon {
  color: #1f1f1f;
}

.base-map-switcher__thumb {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.1);
  flex-shrink: 0;
}

.base-map-switcher__icon {
  width: 16px;
  height: 16px;
  color: rgba(255, 255, 255, 0.8);
}

.base-map-switcher__check {
  position: absolute;
  top: -2px;
  right: -2px;
  width: 8px;
  height: 8px;
  background: #ffffff;
  border-radius: 50%;
  border: 1px solid #1f1f1f;
}

.base-map-switcher__meta {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  flex: 1;
  min-width: 0;
}

.base-map-switcher__name {
  font-size: 13px;
  font-weight: 500;
  line-height: 1.4;
}

.base-map-switcher__count {
  font-size: 11px;
  color: rgba(255, 255, 255, 0.6);
  line-height: 1.2;
}

.base-map-panel-enter-active,
.base-map-panel-leave-active {
  transition: opacity 0.24s ease, transform 0.24s ease;
}

.base-map-panel-enter-from,
.base-map-panel-leave-to {
  opacity: 0;
  transform: translateX(12px);
}
</style>
