<template>
  <div ref="mapContainer" class="map-container" :class="{ 'fullscreen': isFullscreen }">
    <button class="fullscreen-btn" @click="toggleFullscreen">
      {{ isFullscreen ? '退出全屏' : '全屏' }}
    </button>
  </div>
</template>

<script setup>
import { ref, onMounted, watch, defineEmits, onBeforeUnmount } from 'vue'
import * as d3 from 'd3'
import chinaData from './newJson.json'

// ==================== 常量与类型定义 ====================
const DEFAULT_MAP_SIZE = { width: 800, height: 600 }
const PROJECTION_CENTER = [104, 37] // 中国地理中心近似坐标
const SCALE_FACTORS = { normal: 600, fullscreen: 1000 }

// ==================== 组件Props/Emits ====================
const props = defineProps({
  coordinates: {
    type: Array,
    default: () => [
      [116.405285, 39.904989], // 北京
      [121.472644, 31.231706]  // 上海
    ],
    validator: value => value.every(coord => 
      Array.isArray(coord) && coord.length === 2 &&
      typeof coord[0] === 'number' && typeof coord[1] === 'number'
    )
  },
  qvehuan: {
    type: Boolean,
    default: false
  }
})

const emit = defineEmits(['qvehuan1'])

// ==================== 响应式状态 ====================
const mapContainer = ref(null)
const isFullscreen = ref(false)
const isRouteInitialized = ref(false) // 原initqie，重命名以明确含义

// ==================== D3相关变量 ====================
let svgInstance = null
let mapGroup = null
let markersGroup = null
let zoomBehavior = null

// ==================== 地图核心逻辑 ====================
/**
 * 创建地理投影配置
 * @returns {d3.GeoProjection} D3地理投影实例
 */
const createProjection = () => {
  const { width, height } = getContainerSize()
  return d3.geoMercator()
    .center(PROJECTION_CENTER)
    .scale(isFullscreen.value ? SCALE_FACTORS.fullscreen : SCALE_FACTORS.normal)
    .translate([width / 2, height / 2])
}

/**
 * 初始化地图基础结构
 */
const initializeMap = () => {
  // 清理旧实例
  if (svgInstance) svgInstance.remove()

  const { width, height } = getContainerSize()
  const projection = createProjection()
  const pathGenerator = d3.geoPath().projection(projection)

  // 创建SVG容器
  svgInstance = d3.select(mapContainer.value)
    .append('svg')
    .attr('width', width)
    .attr('height', height)

  // 创建分层结构
  const mainGroup = svgInstance.append('g')
  mapGroup = mainGroup.append('g').attr('class', 'map-layer')
  markersGroup = mainGroup.append('g').attr('class', 'markers-layer')

  // 绘制中国地图
  renderChinaMap(pathGenerator)
  
  // 初始化缩放行为
  initializeZoomBehavior(mainGroup)
}

/**
 * 渲染中国地图路径和文字
 * @param {d3.GeoPath} path - 路径生成器
 */
const renderChinaMap = (path) => {
  // 绘制省份路径
  mapGroup.append('g')
    .selectAll('path')
    .data(chinaData.features)
    .enter()
    .append('path')
    .attr('d', path)
    .attr('fill', '#e7e7e7')
    .attr('stroke', '#fff')

  // 添加省份名称
  mapGroup.append('g')
    .selectAll('text')
    .data(chinaData.features)
    .enter()
    .append('text')
    .attr('transform', d => `translate(${path.centroid(d)})`)
    .text(d => d.properties.name || '')
    .attr('text-anchor', 'middle')
    .attr('dominant-baseline', 'central')
    .style('font', '12px Arial')
    .attr('fill', '#333')
    .style('pointer-events', 'none')
}

/**
 * 初始化缩放行为
 * @param {d3.Selection} group - 需要应用缩放的分组
 */
const initializeZoomBehavior = (group) => {
  zoomBehavior = d3.zoom()
    .scaleExtent([0.2, 68])
    .on('zoom', ({ transform }) => {
      group.attr('transform', transform)
    })
  svgInstance.call(zoomBehavior)
}

// ==================== 路线相关逻辑 ====================
/**
 * 更新路线和标记点
 */
const updateRoute = () => {
  if (!props.coordinates?.length) return
  if (!mapGroup) initializeMap()
  const projection = createProjection()
  const pathGenerator = d3.geoPath().projection(projection)

  // 清理旧数据
  if (isRouteInitialized.value) {
    mapGroup.selectAll('.route-path').remove()
    markersGroup.selectAll('*').remove()
    isRouteInitialized.value = false
    emit('qvehuan1', isRouteInitialized.value)
  }

  // 绘制新路线
  renderRoutePath(pathGenerator)
  renderMarkers(projection)
}

/**
 * 绘制路径动画
 * @param {d3.GeoPath} path - 路径生成器
 */
const renderRoutePath = (path) => {
  const routeData = {
    type: "LineString",
    coordinates: props.coordinates
  }

  mapGroup.append('path')
    .datum(routeData)
    .attr('class', 'route-path')
    .attr('d', path)
    .attr('fill', 'none')
    .attr('stroke', '#f00')
    .attr('stroke-width', 0.1)
    .attr('stroke-dasharray', function() {
      return this.getTotalLength()
    })
    .attr('stroke-dashoffset', function() {
      return this.getTotalLength()
    })
    .transition()
    .duration(2000)
    .attr('stroke-dashoffset', 0)
}

/**
 * 绘制位置标记点
 * @param {d3.GeoProjection} projection - 地理投影实例
 */
const renderMarkers = (projection) => {
  props.coordinates.forEach(coord => {
    if (!isValidCoordinate(coord)) return

    const [x, y] = projection(coord)
    markersGroup.append('circle')
      .attr('cx', x)
      .attr('cy', y)
      .attr('r', 0.3)
      .attr('fill', '#ff4757')
      .attr('stroke', 'white')
      .attr('stroke-width', 0)
  })
}

// ==================== 工具函数 ====================
const getContainerSize = () => ({
  width: mapContainer.value?.clientWidth || DEFAULT_MAP_SIZE.width,
  height: mapContainer.value?.clientHeight || DEFAULT_MAP_SIZE.height
})

const isValidCoordinate = (coord) => 
  Array.isArray(coord) && coord.length === 2 &&
  !isNaN(coord[0]) && !isNaN(coord[1])

// ==================== 全屏处理 ====================
const handleWindowResize = () => {
  if (!isFullscreen.value) return
  initializeMap()
  updateRoute()
}

const toggleFullscreen = () => {
  isFullscreen.value = !isFullscreen.value
  setTimeout(() => {
    initializeMap()
    updateRoute()
  }, 100) // 等待DOM更新
}

// ==================== 生命周期钩子 ====================
onMounted(() => {
  window.addEventListener('resize', handleWindowResize)
  // 强制初始化地图基础结构
  initializeMap() // [!code ++]
  // 仅在coordinates存在时更新路线
  if (props.coordinates?.length) { // [!code ++]
    updateRoute() // [!code ++]
  } // [!code ++]
})

onBeforeUnmount(() => {
  window.removeEventListener('resize', handleWindowResize)
})

// ==================== 响应式监听 ====================
watch(() => props.qvehuan, (newVal) => {
  isRouteInitialized.value = newVal
  updateRoute()
})

watch(() => props.coordinates, () => {
  updateRoute()
}, { deep: true })
</script>

<style>
.map-container {
  position: relative;
  background-color: #f0f8ff;
  margin: 20px;
  overflow: hidden;
  touch-action: none;
  transition: all 0.3s ease;
  width: 100%;
  height: 100%;
}

.fullscreen {
  position: fixed !important;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  margin: 0 !important;
  z-index: 1000;
}

.fullscreen-btn {
  position: absolute;
  top: 10px;
  right: 25px;
  z-index: 1001;
  padding: 8px 16px;
  background: rgba(0, 0, 0, 0.7);
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: opacity 0.2s;
}

.fullscreen-btn:hover {
  opacity: 0.9;
}
</style>