<template>
  <div class="calibration-container">
    <!-- 地图舞台容器 -->
    <div class="map-stage" ref="mapStageRef">
      <!-- 地图底层 -->
      <div class="map-canvas-wrapper">
        <OlMap 
          ref="olmapRef" 
          :width="olWidth + 'px'" 
          :height="olHeight + 'px'" 
          backgroundColor="#F5F5F5"
          :robotPoseData="laserPositionData" 
          :poseCalibrationIndex="nowCalibId"
          :showDefaultControls="false"
          :mapName="mapName"
        />
      </div>

      <!-- 地图工具条 -->
      <MapToolbar 
        class="map-toolbar"
        preset="calibration"
        :canAddCalibration="canAddCalibration"
        :hasRobotPosition="hasRobotPosition"
        :isFullscreen="isFullscreen"
        :isConnected="wsConnected"
        :isBusy="false"
        @zoom-in="handleZoomIn"
        @zoom-out="handleZoomOut"
        @center-robot="handleCenterToRobot"
        @toggle-fullscreen="handleToggleFullscreen"
        @add-calibration-point="addCalibration"
      />

      <!-- 右侧信息面板 (宽屏模式，浮层) -->
      <RightPanel 
        v-if="!isMobileMode"
        mode="calib"
        class="right-panel"
        v-model="isPanelVisible"
        :width="rightPanelWidth"
        :title="'实时标定信息'"
        :subtitle="`(当前地图: ${currentMap.name})`"
        :laserPositionData="laserPositionData"
        :gnssPositionData="gnssPositionData"
        :calibrationList="calibrationList"
        :currentMap="currentMap"
        :panelWidth="rightPanelWidth"
        :mapName="mapName"
        @panel-resize="handlePanelResize"
        @add-calibration="addCalibration"
        @remove-calibration="removeCalibration"
        @execute-calibration="executeCalibration"
      />

      <!-- 右上角信息按钮 (窄屏模式) -->
      <div class="info-toggle-btn" v-if="isMobileMode" @click="showInfoDrawer">
        <el-button type="primary" :icon="InfoFilled" circle size="small" />
      </div>
    </div>

    <!-- 抽屉模式 (窄屏) -->
    <el-drawer
      v-model="drawerVisible"
      direction="rtl"
      :modal="false"
      size="360px"
      :with-header="false"
      custom-class="info-drawer"
      :wrapperClosable="false"
      v-if="isMobileMode"
    >
      <div class="drawer-content">
        <div class="drawer-header">
          <div class="drawer-title">
            <h3>实时标定信息</h3>
            <span class="map-name">(当前地图: {{ currentMap.name }})</span>
          </div>
          <el-button 
            @click="drawerVisible = false" 
            type="text" 
            size="small" 
            :icon="Close"
          />
        </div>
        
        <div class="drawer-body">
          <RightPanel 
            :laserPositionData="laserPositionData"
            :gnssPositionData="gnssPositionData"
            :calibrationList="calibrationList"
            :currentMap="currentMap"
            :isDrawerMode="true"
            @add-calibration="addCalibration"
            @remove-calibration="removeCalibration"
            @execute-calibration="executeCalibration"
            class="drawer-panel"
          />
        </div>
      </div>
    </el-drawer>
  </div>
</template>

<script setup>
import { ref, reactive, computed, watch, onMounted, onBeforeUnmount, nextTick } from 'vue'
import { useRoute } from 'vue-router'
import { ElMessage } from 'element-plus'
import { InfoFilled, Close } from '@element-plus/icons-vue'
import OlMap from "@/components/OlMap"
import MapToolbar from "../components/shared/MapToolbar.vue"
import RightPanel from "../components/shared/RightPanel.vue"
import { getCalibrationHistory } from "@/api/robot/map"
import { initWebSocket, disconnect, subscribe, unsubscribe } from "@/utils/websocket"
import { sendMqttMessage } from "@/api/robot/mqtt"

defineOptions({
  name: 'CalibrationPage'
})

// === Route ===
const route = useRoute()

// === Template Refs ===
const mapStageRef = ref(null)
const olmapRef = ref(null)

// === Reactive State ===
const mapName = ref(route.query.mapName || 'Unknown')

const topics = ref([
  '/localization/pose',
  '/settings/multi_coordinates/action/calibrate/reply'
])

const calibrationList = ref([])

const laserPositionData = reactive({
  x: 0,
  y: 0,
  angle: 0
})

const gnssPositionData = reactive({
  status: '0/0',
  longitude: 0,
  latitude: 0,
  angle: 0,
  satellites: 0
})

const currentMap = reactive({
  name: route.query.mapName || 'Unknown'
})

const olWidth = ref(0)
const olHeight = ref(0)
const nowCalibId = ref(0)

const rightPanelWidth = ref(360)
const isPanelVisible = ref(true)
const windowWidth = ref(window.innerWidth)
const drawerVisible = ref(false)
const isFullscreen = ref(false)

const wsConnected = ref(false)
const wsSubscriptions = ref([])

// === Computed ===
const isMobileMode = computed(() => {
  return windowWidth.value < 1440
})

const canAddCalibration = computed(() => {
  return laserPositionData.x !== 0 || laserPositionData.y !== 0
})

const hasRobotPosition = computed(() => {
  return laserPositionData.x !== 0 || laserPositionData.y !== 0
})

// === WebSocket ===
const setupWebSocket = () => {
  initWebSocket({
    onConnect: () => {
      wsConnected.value = true
      console.log('WebSocket连接成功')
    },
    onDisconnect: () => {
      wsConnected.value = false
      console.log('WebSocket连接断开')
    },
    onMessage: (type, message) => {
      handleWsMessage(type, message)
    },
    onError: (error) => {
      console.error('WebSocket错误:', error)
    }
  })
}

const handleWsMessage = (type, message) => {
  try {
    // 处理位姿数据
    if (type === 'pose') {
      const data = message.data || message
      const { xyz, rpy, blh, heading } = data.pose || data
      
      if (xyz) {
        laserPositionData.x = xyz[0] || 0
        laserPositionData.y = xyz[1] || 0
        laserPositionData.angle = rpy ? rpy[2] : 0
      }
      
      if (blh) {
        gnssPositionData.longitude = blh[1] || 0
        gnssPositionData.latitude = blh[0] || 0
        gnssPositionData.angle = heading || 0
      }
      
      if (data.rtk) {
        gnssPositionData.satellites = data.rtk.star || 0
        gnssPositionData.status = `${data.rtk.star || 0}/${data.rtk.status || 0}`
      }
    }
    // 处理标定响应
    else if (type === 'raw' && message.topic && message.topic.includes('/calibrate/reply')) {
      const payload = message.payload || message
      if (payload.status === 'ok') {
        ElMessage.success('标定执行成功')
      } else {
        ElMessage.error('标定执行失败: ' + (payload.error || '未知错误'))
      }
    }
  } catch (e) {
    console.error('消息解析失败:', e)
  }
}

// === Map Methods ===
const updateOlCss = () => {
  nextTick(() => {
    const mapStage = mapStageRef.value
    if (mapStage) {
      olWidth.value = mapStage.offsetWidth
      olHeight.value = mapStage.offsetHeight
      
      if (olmapRef.value?.map) {
        olmapRef.value.map.updateSize()
      }
    }
  })
}

const handleWindowResize = () => {
  windowWidth.value = window.innerWidth
  updateOlCss()
}

const handleFullscreenChange = () => {
  isFullscreen.value = !!(
    document.fullscreenElement ||
    document.webkitFullscreenElement ||
    document.mozFullScreenElement ||
    document.msFullscreenElement
  )
  
  setTimeout(() => {
    updateOlCss()
  }, 100)
}

const updateRightPanelWidth = () => {
  if (isMobileMode.value) {
    isPanelVisible.value = false
  } else {
    const savedWidth = localStorage.getItem('calibration-panel-width')
    const savedCollapsed = localStorage.getItem('calibration-panel-collapsed')
    
    if (savedCollapsed === 'true') {
      isPanelVisible.value = false
      rightPanelWidth.value = 360
    } else if (savedWidth) {
      rightPanelWidth.value = Math.max(320, Math.min(420, parseInt(savedWidth)))
      isPanelVisible.value = true
    } else {
      rightPanelWidth.value = 360
      isPanelVisible.value = true
    }
  }
  
  updateOlCss()
}

const handlePanelResize = (newWidth) => {
  rightPanelWidth.value = newWidth
}

const showInfoDrawer = () => {
  drawerVisible.value = true
}

const getMapInstance = () => {
  return olmapRef.value?.map || null
}

const handleZoomIn = () => {
  try {
    const map = getMapInstance()
    if (map) {
      const view = map.getView()
      view.animate({
        zoom: view.getZoom() + 1,
        duration: 250
      })
    }
  } catch (error) {
    console.warn('地图放大失败:', error)
    ElMessage.warning('地图放大失败')
  }
}

const handleZoomOut = () => {
  try {
    const map = getMapInstance()
    if (map) {
      const view = map.getView()
      view.animate({
        zoom: Math.max(view.getZoom() - 1, 1),
        duration: 250
      })
    }
  } catch (error) {
    console.warn('地图缩小失败:', error)
    ElMessage.warning('地图缩小失败')
  }
}

const handleCenterToRobot = () => {
  try {
    const map = getMapInstance()
    if (map) {
      const view = map.getView()
      
      let centerPoint = [laserPositionData.x, laserPositionData.y]
      if (laserPositionData.x === 0 && laserPositionData.y === 0) {
        centerPoint = view.getCenter()
      }
      
      view.animate({
        center: centerPoint,
        zoom: Math.max(view.getZoom(), 15),
        duration: 500
      })
      ElMessage.success('已定位到机器人位置')
    }
  } catch (error) {
    console.warn('定位机器人失败:', error)
    ElMessage.warning('定位机器人失败')
  }
}

const handleToggleFullscreen = () => {
  try {
    const mapStage = mapStageRef.value
    if (!mapStage) return
    
    if (!isFullscreen.value) {
      if (mapStage.requestFullscreen) {
        mapStage.requestFullscreen()
      } else if (mapStage.webkitRequestFullscreen) {
        mapStage.webkitRequestFullscreen()
      } else if (mapStage.mozRequestFullScreen) {
        mapStage.mozRequestFullScreen()
      } else if (mapStage.msRequestFullscreen) {
        mapStage.msRequestFullscreen()
      }
      isFullscreen.value = true
    } else {
      if (document.exitFullscreen) {
        document.exitFullscreen()
      } else if (document.webkitExitFullscreen) {
        document.webkitExitFullscreen()
      } else if (document.mozCancelFullScreen) {
        document.mozCancelFullScreen()
      } else if (document.msExitFullscreen) {
        document.msExitFullscreen()
      }
      isFullscreen.value = false
    }
    
    setTimeout(() => {
      updateOlCss()
    }, 100)
  } catch (error) {
    console.warn('全屏切换失败:', error)
    ElMessage.warning('全屏功能不可用')
  }
}

// === Calibration Methods ===
const addCalibration = () => {
  if (laserPositionData.x === 0 && laserPositionData.y === 0) {
    ElMessage.warning('当前没有有效的激光定位数据')
    return
  }
  
  const hasValidGnss = gnssPositionData.longitude !== 0 || gnssPositionData.latitude !== 0
  if (!hasValidGnss) {
    ElMessage.warning('当前没有有效的GNSS数据')
    return
  }
  
  // 重新编号保证ID连续
  calibrationList.value = calibrationList.value.map((item, index) => ({
    ...item,
    id: index + 1
  }))
  
  const newId = calibrationList.value.length + 1
  const coordinate = `${laserPositionData.x},${laserPositionData.y}`
  
  const statusParts = gnssPositionData.status.split('/')
  const rtkStatus = parseInt(statusParts[1]) || 0
  
  const data = { 
    id: newId, 
    coordinate, 
    angle: laserPositionData.angle,
    gnss: {
      latitude: gnssPositionData.latitude,
      longitude: gnssPositionData.longitude,
      heading: gnssPositionData.angle,
      status: rtkStatus,
      satellites: gnssPositionData.satellites
    }
  }
  
  calibrationList.value.push(data)
  nowCalibId.value = newId
  
  ElMessage.success(`已添加标定点 ${newId}`)
  
  nextTick(() => {
    displayCalibrationPointsOnMap()
  })
}

const removeCalibration = (id) => {
  if (calibrationList.value.length < 1) return
  
  calibrationList.value = calibrationList.value.filter(item => item.id !== id)
  
  // 重新编号保证ID连续
  calibrationList.value = calibrationList.value.map((item, index) => ({
    ...item,
    id: index + 1
  }))
  
  nowCalibId.value = -1
  
  nextTick(() => {
    displayCalibrationPointsOnMap()
  })
}

const loadHistoryCalibrationData = async () => {
  try {
    const response = await getCalibrationHistory(mapName.value)
    console.log('加载历史标定数据响应:', response.calibration)
    
    if (response.calibration && Array.isArray(response.calibration)) {
      calibrationList.value = response.calibration.map((item, index) => ({
        id: index + 1,
        coordinate: `${item.x},${item.y}`,
        angle: item.yaw,
        gnss: {
          latitude: item.b,
          longitude: item.l,
          heading: item.heading,
          status: item.status,
          satellites: item.start
        }
      }))
      
      console.log('成功加载历史标定数据:', calibrationList.value.length, '个点')
      
      nextTick(() => {
        displayCalibrationPointsOnMap()
      })
    }
  } catch (error) {
    console.log('未找到历史标定数据或加载失败:', error.message)
  }
}

const displayCalibrationPointsOnMap = () => {
  const olmap = olmapRef.value
  if (!olmap || calibrationList.value.length === 0) {
    return
  }
  
  const displayPoints = () => {
    if (!olmap.map) {
      setTimeout(displayPoints, 100)
      return
    }
    
    try {
      olmap.calibrationList = []
      
      calibrationList.value.forEach(item => {
        const coords = item.coordinate.split(',')
        const x = parseFloat(coords[0])
        const y = parseFloat(coords[1])
        
        olmap.calibrationList.push({
          id: item.id,
          x: x,
          y: y
        })
      })
      
      if (olmap.refreshCalibrationOverlays) {
        olmap.refreshCalibrationOverlays()
      }
      
      console.log('已在地图上显示', calibrationList.value.length, '个历史标定点')
    } catch (error) {
      console.error('显示标定点失败:', error)
    }
  }
  
  displayPoints()
}

const executeCalibration = async () => {
  if (calibrationList.value.length < 1) {
    ElMessage.warning('请先添加标定点!')
    return
  }
  
  const hasValidGnss = gnssPositionData.longitude !== 0 || gnssPositionData.latitude !== 0
  if (!hasValidGnss) {
    ElMessage.warning('GNSS数据无效，请确保设备已获取定位信息')
    return
  }
  
  const calibrationData = calibrationList.value.map(item => {
    const coords = item.coordinate.split(',')
    const x = parseFloat(coords[0])
    const y = parseFloat(coords[1])
    
    const statusParts = gnssPositionData.status.split('/')
    const rtkStatus = parseInt(statusParts[1]) || 0
    
    return {
      x: x,
      y: y,
      yaw: item.angle,
      b: item.gnss ? item.gnss.latitude : gnssPositionData.latitude,
      l: item.gnss ? item.gnss.longitude : gnssPositionData.longitude,
      heading: item.gnss ? item.gnss.heading : gnssPositionData.angle,
      status: item.gnss ? item.gnss.status : rtkStatus,
      start: item.gnss ? item.gnss.satellites : gnssPositionData.satellites
    }
  })
  
  const mqttMessage = {
    args: [
      {
        roadmap: mapName.value,
        calibration: calibrationData
      }
    ]
  }
  
  const topic = '/settings/multi_coordinates/action/calibrate'
  
  console.log('发送标定请求:', topic, mqttMessage)
  
  try {
    await sendMqttMessage(topic, mqttMessage)
    ElMessage.success('标定请求已发送，请等待响应...')
  } catch (error) {
    console.error('发送标定请求失败:', error)
    ElMessage.error('发送标定请求失败，请稍后重试')
  }
}

// === Watch ===
watch(windowWidth, (newWidth) => {
  if (newWidth < 1440) {
    drawerVisible.value = false
  }
  updateRightPanelWidth()
})

watch(drawerVisible, () => {
  nextTick(() => {
    updateOlCss()
  })
})

watch(isPanelVisible, (newVal) => {
  localStorage.setItem('calibration-panel-collapsed', String(!newVal))
  nextTick(() => {
    updateOlCss()
  })
})

// === Lifecycle ===
onMounted(() => {
  // 从 localStorage 恢复状态
  const savedPanelWidth = localStorage.getItem('calibration-panel-width')
  const savedPanelCollapsed = localStorage.getItem('calibration-panel-collapsed')
  
  if (savedPanelWidth) {
    rightPanelWidth.value = Math.max(320, Math.min(420, parseInt(savedPanelWidth)))
  }
  if (savedPanelCollapsed) {
    isPanelVisible.value = savedPanelCollapsed !== 'true'
  }
  
  // 监听窗口大小变化
  window.addEventListener('resize', handleWindowResize)
  
  // 监听全屏状态变化
  document.addEventListener('fullscreenchange', handleFullscreenChange)
  document.addEventListener('webkitfullscreenchange', handleFullscreenChange)
  document.addEventListener('mozfullscreenchange', handleFullscreenChange)
  document.addEventListener('MSFullscreenChange', handleFullscreenChange)
  
  // 初始设置面板宽度
  updateRightPanelWidth()
  
  // 初始化WebSocket连接
  setupWebSocket()
  
  // 加载历史标定数据
  loadHistoryCalibrationData()
})

onBeforeUnmount(() => {
  window.removeEventListener('resize', handleWindowResize)
  document.removeEventListener('fullscreenchange', handleFullscreenChange)
  document.removeEventListener('webkitfullscreenchange', handleFullscreenChange)
  document.removeEventListener('mozfullscreenchange', handleFullscreenChange)
  document.removeEventListener('MSFullscreenChange', handleFullscreenChange)
  
  // 断开WebSocket连接
  disconnect()
})
</script>

<style lang="scss" scoped>
.calibration-container {
  width: 100%;
  height: calc(100vh - 84px);
  min-height: 600px;
  background: var(--color-bg-secondary);
  position: relative;
  overflow: hidden;

  .map-stage {
    position: relative;
    width: 100%;
    height: 100%;
    background: var(--color-bg-card);
    border-radius: var(--radius-lg);
    overflow: hidden;
    box-shadow: var(--shadow-card);

    .map-canvas-wrapper {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      z-index: 1;
    }

    .map-toolbar {
      position: absolute;
      left: 16px;
      top: 16px;
      z-index: 50;
      pointer-events: auto;
    }

    .right-panel {
      position: absolute;
      right: 16px;
      top: 16px;
      height: calc(100% - 32px);
      z-index: 10;
      border-radius: var(--radius-lg);
      box-shadow: var(--shadow-xl);
      background: var(--color-bg-card);
      display: flex;
      flex-direction: column;
      pointer-events: auto;
      transition: all var(--duration-200) var(--ease-out);

      &.panel-collapsed {
        width: 0 !important;
        opacity: 0;
        pointer-events: none;
        overflow: hidden;
      }
    }

    .panel-reopen-btn {
      position: absolute;
      right: 0;
      top: 50%;
      transform: translateY(-50%);
      z-index: 12;
      width: 36px;
      height: 72px;
      background: var(--color-bg-card);
      border: 1px solid var(--color-border-primary);
      border-radius: 8px 0 0 8px;
      box-shadow: var(--shadow-lg);
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      color: var(--color-text-secondary);
      transition: all var(--duration-200) var(--ease-out);
      pointer-events: auto;

      &:hover {
        background: var(--color-primary);
        color: var(--color-text-inverse);
        border-color: var(--color-primary);
        transform: translateY(-50%) translateX(-2px);
        box-shadow: var(--shadow-xl);
      }
    }

    .info-toggle-btn {
      position: absolute;
      top: 16px;
      right: 16px;
      z-index: 10;
      pointer-events: auto;
      
      .el-button {
        box-shadow: var(--shadow-lg);
      }
    }
  }
}

/* 抽屉样式 */
.drawer-content {
  height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--color-bg-card);

  .drawer-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--spacing-4);
    border-bottom: 1px solid var(--color-border-secondary);
    background: var(--color-bg-tertiary);

    .drawer-title {
      h3 {
        margin: 0;
        font-size: var(--font-size-lg);
        font-weight: var(--font-weight-semibold);
        color: var(--color-text-primary);
        line-height: var(--line-height-tight);
      }

      .map-name {
        font-size: var(--font-size-xs);
        color: var(--color-danger);
        margin-left: var(--spacing-2);
      }
    }
  }

  .drawer-body {
    flex: 1;
    overflow: hidden;

    .drawer-panel {
      height: 100%;
      
      :deep(.panel-header) {
        display: none;
      }
      
      :deep(.panel-content) {
        height: 100%;
        padding: var(--spacing-4);
      }

      :deep(.resize-handle) {
        display: none;
      }
    }
  }
}

/* 响应式设计 */
@media (max-width: 1439px) {
  .calibration-container {
    .map-stage {
      .right-panel {
        display: none;
      }
    }
  }
}

@media (max-width: 768px) {
  .calibration-container {
    height: calc(100vh - 60px);
    
    .map-stage {
      border-radius: 0;

      .map-toolbar {
        left: 12px;
        top: 12px;
      }

      .panel-reopen-btn {
        width: 32px;
        height: 60px;
      }

      .info-toggle-btn {
        top: 12px;
        right: 12px;
      }
    }
  }
}

/* 动画效果 */
@keyframes slideInRight {
  from {
    opacity: 0;
    transform: translateX(20px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes slideInUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.calibration-container {
  animation: slideInUp 0.3s ease-out;
}

.info-toggle-btn {
  animation: slideInRight 0.3s ease-out 0.2s both;
}

/* 暗色主题适配 */
html.dark {
  .calibration-container {
    .map-stage {
      background: var(--color-bg-tertiary);
      box-shadow: var(--shadow-card);

      .right-panel {
        background: var(--color-bg-tertiary);
        border-color: var(--color-border-tertiary);
        box-shadow: var(--shadow-xl);
      }

      .panel-reopen-btn {
        background: var(--color-bg-tertiary);
        border-color: var(--color-border-tertiary);

        &:hover {
          background: var(--color-primary);
          border-color: var(--color-primary);
        }
      }
    }
  }

  .drawer-content {
    background: var(--color-bg-tertiary);

    .drawer-header {
      background: var(--color-bg-quaternary);
      border-bottom-color: var(--color-border-tertiary);
    }
  }
}
</style>

<style>
/* 全局抽屉样式 */
.info-drawer {
  background-color: var(--color-bg-card);
  box-shadow: var(--shadow-xl);
  border-radius: var(--radius-lg) 0 0 var(--radius-lg);
}

.info-drawer .el-drawer__body {
  padding: 0;
  height: 100%;
  overflow: hidden;
}

/* 暗色主题抽屉样式 */
html.dark .info-drawer {
  background-color: var(--color-bg-tertiary);
  box-shadow: var(--shadow-xl);
}
</style>
