<template>
  <div
    v-if="showCompass"
    :class="compassClasses"
    :style="compassStyle"
    @click="recoverHeading"
    title="点击恢复正北方向"
  >
    <!-- 指南针背景 - 根据相机朝向旋转 -->
    <img
      src="@/map/assets/icons/compass_bg.svg"
      alt="指南针背景"
      class="compass-bg"
      :style="{ transform: `rotate(${-heading}deg)` }"
    />

    <!-- 指南针指针 - 固定指向北方 -->
    <img
      src="@/map/assets/icons/compass.svg"
      alt="指南针指针"
      class="compass-needle"
    />
    
    <!-- 方向文字显示 -->
    <div class="direction-text">{{ directionText }}</div>
    
    <!-- 角度数值显示 -->
    <div class="degree-text">{{ displayHeading }}°</div>
  </div>
</template>

<script setup>
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import * as Cesium from 'cesium'
import useMapStore from '@/map/stores/mapStore'

const props = defineProps({
  // 是否显示指南针
  visible: {
    type: Boolean,
    default: true
  },
  // 主题 ('dark' | 'light')
  theme: {
    type: String,
    default: 'light',
    validator: (value) => ['dark', 'light'].includes(value)
  },
  // 自定义样式
  customStyle: {
    type: Object,
    default: () => ({})
  }
})

const mapStore = useMapStore()
const heading = ref(0)
let postRenderListener = null

/**
 * 将角度转换为方向文字
 * @param {number} num - 角度值 (0-360)
 * @returns {string} 方向缩写 (N, NE, E, SE, S, SW, W, NW)
 */
const directionToString = (num) => {
  const n = parseFloat(num)
  const directions = [
    { min: 0, max: 22.5, dir: 'N' },
    { min: 22.5, max: 67.5, dir: 'NE' },
    { min: 67.5, max: 112.5, dir: 'E' },
    { min: 112.5, max: 157.5, dir: 'SE' },
    { min: 157.5, max: 202.5, dir: 'S' },
    { min: 202.5, max: 247.5, dir: 'SW' },
    { min: 247.5, max: 292.5, dir: 'W' },
    { min: 292.5, max: 337.5, dir: 'NW' },
    { min: 337.5, max: 360, dir: 'N' }
  ]
  
  const direction = directions.find(d => n >= d.min && n <= d.max)
  return direction ? direction.dir : 'N'
}

/**
 * 恢复指北方向
 */
const recoverHeading = async () => {
  if (!mapStore.isReady()) return
  
  try {
    const camera = mapStore.services().camera
    const currentView = camera.getCurrentView()
    
    // 保持当前位置，只改变朝向为正北
    await camera.flyTo({
      lon: currentView.lon,
      lat: currentView.lat,
      height: currentView.height,
      heading: 0, // 正北方向
      pitch: currentView.pitch,
      roll: currentView.roll,
      duration: 1.0
    })
  } catch (err) {
    console.warn('Failed to recover heading:', err)
  }
}

// 计算属性
const showCompass = computed(() => props.visible && mapStore.isReady())

const directionText = computed(() => directionToString(heading.value))

const displayHeading = computed(() => {
  const h = heading.value === 360 ? 0 : heading.value
  return h.toString().padStart(3, '0')
})

const compassClasses = computed(() => [
  'map-compass',
  `map-compass--${props.theme}`
])

const compassStyle = computed(() => ({
  ...props.customStyle
}))

// 初始化指南针监听器
const initCompassListener = () => {
  if (!mapStore.isReady()) return

  const viewer = mapStore.getViewer()
  
  postRenderListener = () => {
    if (!viewer?.scene?.camera) {
      return
    }
    const rawHeading = viewer.scene.camera.heading
    if (typeof rawHeading !== 'number' || Number.isNaN(rawHeading)) {
      heading.value = 0
      return
    }
    const currentHeading = Cesium.Math.toDegrees(rawHeading)
    const normalizedHeading = ((currentHeading % 360) + 360) % 360
    heading.value = Math.round(normalizedHeading)
  }
  
  viewer.scene.postRender.addEventListener(postRenderListener)
}

// 清理监听器
const cleanupListener = () => {
  if (postRenderListener && mapStore.isReady()) {
    try {
      const viewer = mapStore.getViewer()
      if (viewer?.scene && !viewer.isDestroyed()) {
        viewer.scene.postRender.removeEventListener(postRenderListener)
      }
    } catch (err) {
      console.warn('Failed to cleanup compass listener:', err)
    }
  }
  postRenderListener = null
}

// 生命周期钩子
onMounted(() => {
  if (mapStore.isReady()) {
    initCompassListener()
  } else {
    // 等待地图就绪
    const detachReadyListener = mapStore.onReady(() => {
      initCompassListener()
      detachReadyListener()
    })
  }
})

onBeforeUnmount(() => {
  cleanupListener()
})

// 监听地图就绪状态变化
watch(
  () => mapStore.ready,
  (ready) => {
    if (ready) {
      initCompassListener()
    } else {
      cleanupListener()
      heading.value = 0
    }
  }
)
</script>

<style scoped lang="scss">
.map-compass {
  cursor: pointer;
  box-sizing: border-box;
  border-radius: 50%;
  height: 40px;
  width: 40px;
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
  background-color: rgba(255, 255, 255, 0.92);
  transition: background-color 0.2s ease, transform 0.2s ease;
  user-select: none;

  // 悬停效果
  &:hover {
    background-color: #ffffff;
    transform: translateY(-1px);
  }

  // 浅色主题 (默认)
  &--light {
    background-color: rgba(255, 255, 255, 0.92);
    color: #333333;

    &:hover {
      background-color: #ffffff;
    }

    .direction-text {
      color: #333333;
    }

    .degree-text {
      color: #555555;
    }
  }

  // 深色主题
  &--dark {
    background-color: rgba(28, 49, 58, 0.92);
    color: #ffffff;

    &:hover {
      background-color: rgba(28, 49, 58, 0.8);
    }

    .direction-text {
      color: #ffffff;
    }

    .degree-text {
      color: #ffffff;
    }

  }
}

// 指南针背景图片样式
.compass-bg {
  width: 56px;
  height: 56px;
  transition: transform 0.2s ease-out;
  
  // 深色主题下的背景颜色调整
  .darkTheme & {
    filter: invert(1) sepia(1) saturate(2) hue-rotate(180deg) brightness(0.3) contrast(1.2);
  }
}

// 指南针指针样式
.compass-needle {
  width: 40px;
  height: 43px;
  border-radius: 50%;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  
  // 深色主题下的指针颜色调整
  .darkTheme & {
    filter: invert(1) brightness(0.8);
  }
}

// 方向文字样式 (N, NE, E, SE, S, SW, W, NW)
.direction-text {
  position: absolute;
  left: 50%;
  top: 30%;
  transform: translateX(-50%);
  font-size: 11px;
  font-weight: bold;
  user-select: none;
  z-index: 3;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}

// 角度数值样式 (000°-360°)
.degree-text {
  position: absolute;
  left: 50%;
  top: 65%;
  transform: translateX(-50%);
  font-size: 9px;
  user-select: none;
  z-index: 3;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}

@media (max-width: 768px) {
  .map-compass {
    width: 36px;
    height: 36px;
  }

  .compass-bg {
    width: 36px;
    height: 36px;
  }

  .compass-needle {
    width: 34px;
    height: 36px;
  }

  .direction-text {
    font-size: 10px;
  }

  .degree-text {
    font-size: 8px;
  }
}
</style>
