<template>
  <div class="dispatch-map-container" ref="mapContainer">
    <div class="map-wrapper" ref="mapWrapper" @click.self="hideContextMenu">
      <Amap
        ref="mainMap"
        container-id="dispatch-map"
        width="100%"
        :height="mapHeight"
        :center="mapCenter"
        :zoom="mapZoom"
        :markers="filteredMarkers"
        @marker-click="handleMarkerClick"
        @marker-context="handleMarkerContext"
      />
      <MarkerContextMenu
        v-if="contextMenuVisible"
        :position="contextMenuPosition"
        :type="contextMenuType"
        :payload="contextMenuPayload"
        @action="handleContextMenuAction"
        @close="hideContextMenu"
      />
      <CreateTaskDialog
        :visible="createTaskDialogVisible"
        :event-id="createTaskEventId"
        :event-data="createTaskEventData"
        @close="createTaskDialogVisible = false"
        @success="handleTaskCreated"
      />
      <!-- 摄像头预览画中画 -->
      <CameraPipPlayer
        v-if="pipVisible"
        :visible="pipVisible"
        :src="pipSrc"
        :type="pipType"
        :title="pipTitle"
        :error="pipError"
        @close="handlePipClose"
        @retry="handleRetry"
        @player-error="handlePlayerError"
      />
    </div>
  </div>
</template>

<script>
import Amap from '@/components/Amap'
import MarkerContextMenu from './MarkerContextMenu.vue'
import CreateTaskDialog from './CreateTaskDialog.vue'
import { listEvents, pinEvent, unpinEvent } from '@/api/emergency/event'
import { listTeam } from '@/api/resource/team'
import { listWarehouse } from '@/api/resource/warehouse'
import { listExpert } from '@/api/resource/expert'
import { listVehicle } from '@/api/resource/vehicle'
import { listCamera, startCameraStream, stopCameraStream, getCameraPlayUrls } from '@/api/camera'
import { buildFullPlayUrls } from '@/utils/camera/stream'
import CameraPipPlayer from '@/components/CameraPipPlayer'
import { buildMapIcon, buildMarkerIconUri } from '@/utils/mapIcons'

export default {
  name: 'DispatchMap',
  components: {
    Amap,
    MarkerContextMenu,
    CreateTaskDialog,
    CameraPipPlayer
  },
  props: {
    visibleLayers: {
      type: Array,
      default: () => ['events', 'teams', 'warehouses', 'experts', 'vehicles']
    },
    highlightMarkerId: {
      type: String,
      default: null
    }
  },
  data() {
    return {
      mapCenter: [120.1551, 30.2741], // 默认中心点（杭州）
      mapZoom: 12,
      mapHeight: '500px',
      allMarkers: [], // 所有标记数据
      refreshTimer: null,
      resizeObserver: null,
      layerColors: {
        events: '#FF9800',
        teams: '#67C23A',
        warehouses: '#909399',
        experts: '#F56C6C',
        vehicles: '#8B5CF6',
        cameras: '#409EFF'
      },
      layerLabels: {
        events: '事件',
        teams: '队伍',
        warehouses: '仓库',
        experts: '专家',
        vehicles: '车辆',
        cameras: '摄像头'
      },
      contextMenuVisible: false,
      contextMenuPosition: { left: 0, top: 0 },
      contextMenuType: null,
      contextMenuPayload: null,
      createTaskDialogVisible: false,
      createTaskEventId: null,
      createTaskEventData: null,
      // 摄像头预览画中画状态
      pipVisible: false,
      pipSrc: '',
      pipType: 'hls',
      pipTitle: '',
      pipError: null,
      previewCamera: null,
      heartbeatTimer: null
    }
  },
  computed: {
    filteredMarkers() {
      return this.allMarkers
        .filter(marker => this.visibleLayers.includes(marker.type))
        .map(marker => {
          // Highlight based on importance (importantFlag), allowing multiple highlights
          const isHighlighted = marker.type === 'events' && marker.data?.importantFlag === 1
          return {
            lat: marker.lat,
            lng: marker.lng,
            title: marker.name,
            typeLabel: marker.typeLabel, // For LabelMarker text
            content: this.buildMarkerContent(marker),
            color: marker.color,
            icon: this.buildMarkerIcon(marker, isHighlighted),
            isHighlighted,
            markerData: marker
          }
        })
    },
    filteredMarkerList() {
      return this.allMarkers.filter(marker => this.visibleLayers.includes(marker.type))
    }
  },
  watch: {
    visibleLayers: {
      handler() {
        this.$nextTick(() => {
          this.setupMarkerClickHandlers()
        })
      },
      deep: true
    },
    highlightMarkerId(newVal) {
      if (newVal) {
        this.highlightMarker(newVal)
      }
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.updateMapHeight()
      
      if (window.ResizeObserver && this.$refs.mapContainer) {
        this.resizeObserver = new ResizeObserver(() => {
          this.updateMapHeight()
        })
        this.resizeObserver.observe(this.$refs.mapContainer)
      } else {
        window.addEventListener('resize', this.updateMapHeight)
      }
    })
    
    this.loadAllMarkers()
    this.refreshTimer = setInterval(() => {
      this.loadAllMarkers()
    }, 60000)
  },
  beforeDestroy() {
    if (this.refreshTimer) {
      clearInterval(this.refreshTimer)
      this.refreshTimer = null
    }
    if (this.resizeObserver) {
      this.resizeObserver.disconnect()
      this.resizeObserver = null
    } else {
      window.removeEventListener('resize', this.updateMapHeight)
    }
    // 清理摄像头预览相关资源
    this.cleanupPreview()
  },
  methods: {
    updateMapHeight() {
      if (this.$refs.mapContainer) {
        const container = this.$refs.mapContainer
        const height = container.offsetHeight || container.clientHeight
        if (height > 100) {
          this.mapHeight = `${height}px`
          if (this.$refs.mainMap && this.$refs.mainMap.map) {
            this.$nextTick(() => {
              try {
                this.$refs.mainMap.map.resize()
              } catch (error) {
                console.warn('地图调整大小失败:', error)
              }
            })
          }
        }
      }
    },
    async loadAllMarkers() {
      try {
        const params = { 
          pageNum: 1, 
          pageSize: 1000,
          excludeStatuses: ['completed', 'archived'] // 排除已完成和归档的事件
        }
        const [eventsRes, teamsRes, warehousesRes, expertsRes, vehiclesRes, camerasRes] = await Promise.all([
          listEvents(params).catch(() => ({ code: 200, rows: [] })),
          listTeam(params).catch(() => ({ code: 200, rows: [] })),
          listWarehouse(params).catch(() => ({ code: 200, rows: [] })),
          listExpert(params).catch(() => ({ code: 200, rows: [] })),
          listVehicle(params).catch(() => ({ code: 200, rows: [] })),
          listCamera({ pageNum: 1, pageSize: 1000 }).catch(() => ({ code: 200, rows: [] }))
        ])
        
        const markers = []
        
        // 处理事件
        if (eventsRes.code === 200 && Array.isArray(eventsRes.rows)) {
          eventsRes.rows.forEach(event => {
            if (event.longitude && event.latitude) {
              markers.push({
                id: `event-${event.id}`,
                type: 'events',
                typeLabel: this.layerLabels.events,
                name: event.title || event.eventNo || `事件-${event.id}`,
                status: this.getEventStatusLabel(event.status),
                location: event.location || '位置未知',
                lat: parseFloat(event.latitude),
                lng: parseFloat(event.longitude),
                color: this.layerColors.events,
                data: event
              })
            }
          })
        }
        
        // 处理队伍
        if (teamsRes.code === 200 && Array.isArray(teamsRes.rows)) {
          teamsRes.rows.forEach(team => {
            if (team.longitude && team.latitude) {
              markers.push({
                id: `team-${team.id}`,
                type: 'teams',
                typeLabel: this.layerLabels.teams,
                name: team.teamName || `队伍-${team.id}`,
                status: team.status === 'available' ? '可用' : team.status === 'busy' ? '占用' : '停用',
                location: team.locationName || team.contactAddress || '位置未知',
                lat: parseFloat(team.latitude),
                lng: parseFloat(team.longitude),
                color: this.layerColors.teams,
                data: team
              })
            }
          })
        }
        
        // 处理仓库
        if (warehousesRes.code === 200 && Array.isArray(warehousesRes.rows)) {
          warehousesRes.rows.forEach(warehouse => {
            if (warehouse.longitude && warehouse.latitude) {
              markers.push({
                id: `warehouse-${warehouse.id}`,
                type: 'warehouses',
                typeLabel: this.layerLabels.warehouses,
                name: warehouse.warehouseName || `仓库-${warehouse.id}`,
                status: warehouse.status === '0' ? '正常' : '停用',
                location: warehouse.address || '位置未知',
                lat: parseFloat(warehouse.latitude),
                lng: parseFloat(warehouse.longitude),
                color: this.layerColors.warehouses,
                data: warehouse
              })
            }
          })
        }
        
        // 处理专家
        if (expertsRes.code === 200 && Array.isArray(expertsRes.rows)) {
          expertsRes.rows.forEach(expert => {
            if (expert.longitude && expert.latitude) {
              markers.push({
                id: `expert-${expert.id}`,
                type: 'experts',
                typeLabel: this.layerLabels.experts,
                name: expert.expertName || `专家-${expert.id}`,
                status: expert.status === 'active' ? '启用' : expert.status === 'inactive' ? '停用' : '黑名单',
                location: expert.locationName || expert.organization || '位置未知',
                lat: parseFloat(expert.latitude),
                lng: parseFloat(expert.longitude),
                color: this.layerColors.experts,
                data: expert
              })
            }
          })
        }
        
        // 处理车辆
        if (vehiclesRes.code === 200 && Array.isArray(vehiclesRes.rows)) {
          vehiclesRes.rows.forEach(vehicle => {
            if (vehicle.gpsLat && vehicle.gpsLng) {
              markers.push({
                id: `vehicle-${vehicle.id}`,
                type: 'vehicles',
                typeLabel: this.layerLabels.vehicles,
                name: vehicle.vehicleName || vehicle.plateNo || `车辆-${vehicle.id}`,
                status: vehicle.status === 'available' ? '可用' : vehicle.status === 'busy' ? '占用' : vehicle.status || '未知',
                location: vehicle.lastSeenAt ? `最后定位: ${vehicle.lastSeenAt}` : '位置未知',
                lat: parseFloat(vehicle.gpsLat),
                lng: parseFloat(vehicle.gpsLng),
                color: this.layerColors.vehicles,
                data: vehicle
              })
            }
          })
        }

        // 处理摄像头
        if (camerasRes.code === 200 && Array.isArray(camerasRes.rows)) {
          camerasRes.rows.forEach(camera => {
            if (camera.longitude != null && camera.latitude != null) {
              markers.push({
                id: `camera-${camera.id}`,
                type: 'cameras',
                typeLabel: this.layerLabels.cameras,
                name: camera.cameraName || camera.cameraCode || `摄像头-${camera.id}`,
                status: camera.status === 'online' ? '在线' : (camera.status || '未知'),
                location: camera.address || '位置未知',
                lat: parseFloat(camera.latitude),
                lng: parseFloat(camera.longitude),
                color: this.layerColors.cameras,
                data: camera
              })
            }
          })
        }
        
        this.allMarkers = markers
        
        this.$nextTick(() => {
          this.setupMarkerClickHandlers()
        })
        if (this.highlightMarkerId) {
          this.highlightMarker(this.highlightMarkerId)
        }
      } catch (error) {
        console.error('加载地图标记失败:', error)
      }
    },
    buildMarkerContent(marker) {
      // Build icon for info window (no stroke needed)
      const iconSvg = buildMapIcon(marker.type, 16, marker.color, { withStroke: false })
      
      return `
        <div style="padding: 8px; min-width: 180px;">
          <div style="font-weight: 600; margin-bottom: 4px; display: flex; align-items: center; gap: 6px;">
            <span style="display: inline-flex; align-items: center; width: 16px; height: 16px; flex-shrink: 0;">
              ${iconSvg}
            </span>
            <span style="display: inline-block; padding: 2px 6px; background: ${marker.color}; color: #fff; border-radius: 4px; font-size: 11px;">
              ${marker.typeLabel}
            </span>
            ${marker.name}
          </div>
          <div style="font-size: 12px; color: #606266; margin-top: 4px;">
            <div>${marker.status}</div>
            <div>${marker.location}</div>
          </div>
        </div>
      `
    },
    buildMarkerIcon(marker, isHighlighted) {
      const size = isHighlighted ? 48 : 36
      let color = marker.color

      // 摄像头根据状态区分颜色
      if (marker.type === 'cameras') {
        const status = marker.data && marker.data.status
        if (status === 'offline') {
          color = '#909399'
        } else if (status === 'online') {
          color = '#409EFF'
        }
      } else {
        color = isHighlighted ? '#FF4D4F' : marker.color
      }
      
      // Build marker icon with stroke for better visibility on map
      return buildMarkerIconUri(marker.type, size, color, { withStroke: true })
    },
    setupMarkerClickHandlers() {
      // 标记点击事件由 Amap 组件处理，通过 infoWindow 的 content 中我们可以添加点击事件
      // 这里我们通过 $emit 通知父组件
      if (this.$refs.mainMap && this.$refs.mainMap.map) {
        // Amap 组件已经处理了标记点击，我们只需要在需要时触发事件
      }
    },
    handleMarkerClick(event) {
      // 从 Amap 组件接收到的 marker-click 事件
      if (event.data) {
        // event.data 是 markerData，包含 type, id, data 等信息
        const markerData = event.data
        // 摄像头：直接打开画中画预览
        if (markerData.type === 'cameras' && markerData.data) {
          this.handleCameraMarkerClick(markerData.data)
          return
        }
        // markerData 结构: { id: 'team-123', type: 'teams', data: { id: 123, ... } }
        if (markerData.type && markerData.data && markerData.data.id) {
          this.hideContextMenu()
          this.$emit('marker-clicked', {
            type: markerData.type,
            id: markerData.data.id, // 使用 data.id 作为实际资源ID
            data: markerData.data
          })
        }
      }
    },
    handleMarkerContext(event) {
      if (!event || !event.pixel) return
      const wrapper = this.$refs.mapWrapper
      const wrapperRect = wrapper ? wrapper.getBoundingClientRect() : null
      const menuWidth = 180
      const menuHeight = 220
      let left = event.pixel.x
      let top = event.pixel.y
      if (wrapperRect) {
        left = event.pixel.x
        top = event.pixel.y
        left = Math.max(8, Math.min(left, wrapperRect.width - menuWidth - 8))
        top = Math.max(8, Math.min(top, wrapperRect.height - menuHeight - 8))
      }
      this.contextMenuPosition = { left, top }
      this.contextMenuType = event.data?.type || event.type || null
      this.contextMenuPayload = event.data || null
      this.contextMenuVisible = true
    },
    hideContextMenu() {
      this.contextMenuVisible = false
      this.contextMenuType = null
      this.contextMenuPayload = null
    },
    handleContextMenuAction({ action, payload }) {
      if (!action) {
        this.hideContextMenu()
        return
      }
      const [type, operation] = action.split(':')

      if (operation === 'copyInfo') {
        const eventData = payload?.data
        if (eventData) {
          const infoSegments = [
            `事件编号：${eventData.eventNo || eventData.id || '未知'}`,
            `标题：${eventData.title || eventData.eventNo || '未命名事件'}`,
            `状态：${this.getEventStatusLabel(eventData.status)}`,
            `地点：${eventData.location || eventData.address || '未知'}`,
            `发生时间：${eventData.occurredAt || eventData.createTime || '未知'}`
          ]
          const text = infoSegments.join('\n')
          this.copyToClipboard(text)
            .then(() => {
              this.$message.success('事件关键信息已复制')
            })
            .catch(() => {
              this.$message.error('复制失败，请手动复制')
            })
        }
        this.hideContextMenu()
        return
      }

      if (operation === 'pin') {
        const eventData = payload?.data
        if (eventData?.id) {
          const api = eventData.importantFlag === 1 ? unpinEvent : pinEvent
          api(eventData.id)
            .then(() => {
              eventData.importantFlag = eventData.importantFlag === 1 ? 0 : 1
              const message = eventData.importantFlag === 1 ? '已标记为重点事件' : '已取消重点事件'
              this.$message.success(message)
              this.loadAllMarkers()
              this.$emit('event-pin-changed', {
                id: eventData.id,
                important: eventData.importantFlag === 1
              })
            })
            .catch(() => {
              this.$message.error('操作失败，请稍后重试')
            })
        }
        this.hideContextMenu()
        return
      }

      // 摄像头预览处理
      if (operation === 'preview' && type === 'camera') {
        if (payload?.data) {
          this.handleCameraMarkerClick(payload.data)
        }
        this.hideContextMenu()
        return
      }

      if (operation === 'locate') {
        if (payload?.data?.id) {
          const marker = this.allMarkers.find((markerItem) => {
            const dataId = markerItem.data?.id
            if (!dataId) return false
            switch (type) {
              case 'event':
                return markerItem.type === 'events' && dataId === payload.data.id
              case 'team':
                return markerItem.type === 'teams' && dataId === payload.data.id
              case 'warehouse':
                return markerItem.type === 'warehouses' && dataId === payload.data.id
              case 'expert':
                return markerItem.type === 'experts' && dataId === payload.data.id
              case 'vehicle':
                return markerItem.type === 'vehicles' && dataId === payload.data.id
              case 'camera':
                return markerItem.type === 'cameras' && dataId === payload.data.id
              default:
                return false
            }
          })
          if (marker) {
            this.highlightMarker(marker.id)
            this.$emit('marker-located', {
              type: marker.type,
              id: payload.data.id,
              data: payload.data
            })
          }
        }
        this.hideContextMenu()
        return
      }

      if (operation === 'createTask') {
        const eventData = payload?.data
        if (eventData?.id) {
          this.createTaskEventId = eventData.id
          this.createTaskEventData = eventData
          this.createTaskDialogVisible = true
        } else {
          this.$message.warning('无法获取事件信息')
        }
        this.hideContextMenu()
        return
      }

      if (operation === 'view') {
        if (payload?.data) {
          // 摄像头视图：直接打开画中画预览
          if ((payload.type === 'camera' || payload.type === 'cameras') && payload.data) {
            this.handleCameraMarkerClick(payload.data)
          } else {
            this.$emit('marker-clicked', {
              type: payload.type || `${type}s`,
              id: payload.data.id,
              data: payload.data
            })
          }
        }
        this.hideContextMenu()
        return
      }

      this.$emit('context-action', {
        action,
        type,
        operation,
        payload: payload?.data || payload
      })
      this.hideContextMenu()
    },
    /** 摄像头 Marker 点击预览 */
    async handleCameraMarkerClick(camera) {
      const id = camera && camera.id
      if (!id) {
        this.$message.warning('摄像头ID不存在')
        return
      }

      // 立即显示画中画
      this.previewCamera = camera
      this.pipTitle = camera.cameraName || camera.cameraCode || '摄像头预览'
      this.pipSrc = ''
      this.pipVisible = true
      this.pipError = null

      try {
        const res = await startCameraStream(id)
        if (res.code === 200) {
          const urls = buildFullPlayUrls(res.data)
          this.pipSrc = urls.hls || urls.flv || ''
          this.pipType = urls.hls ? 'hls' : 'flv'
          this.pipError = null
          this.startHeartbeat(id)
        } else {
          this.pipError = res.msg || '启动视频流失败'
        }
      } catch (e) {
        this.pipError = '启动视频流失败：' + (e.message || '未知错误')
      }
    },
    /** 关闭画中画 */
    handlePipClose() {
      this.cleanupPreview()
      this.pipVisible = false
      this.pipSrc = ''
      this.pipTitle = ''
      this.pipError = null
      this.previewCamera = null
    },
    /** 重试预览 */
    handleRetry() {
      if (this.previewCamera && this.previewCamera.id) {
        this.pipError = null
        this.pipSrc = ''
        this.handleCameraMarkerClick(this.previewCamera)
      }
    },
    /** 播放器错误 */
    handlePlayerError(msg) {
      this.pipError = msg || '视频播放失败'
    },
    /** 清理预览资源 */
    cleanupPreview() {
      if (this.heartbeatTimer) {
        clearInterval(this.heartbeatTimer)
        this.heartbeatTimer = null
      }
      if (this.previewCamera && this.previewCamera.id) {
        stopCameraStream(this.previewCamera.id).catch(err => {
          // 后端可能已经清理，不阻塞前端
          // eslint-disable-next-line no-console
          console.warn('停止摄像头流失败', err)
        })
      }
    },
    /** 启动心跳，保持流活跃 */
    startHeartbeat(cameraId) {
      if (this.heartbeatTimer) {
        clearInterval(this.heartbeatTimer)
        this.heartbeatTimer = null
      }
      this.heartbeatTimer = setInterval(() => {
        getCameraPlayUrls(cameraId).catch(err => {
          // eslint-disable-next-line no-console
          console.warn('摄像头心跳失败', err)
          if (this.heartbeatTimer) {
            clearInterval(this.heartbeatTimer)
            this.heartbeatTimer = null
          }
        })
      }, 2 * 60 * 1000)
    },
    copyToClipboard(text) {
      if (navigator.clipboard && navigator.clipboard.writeText) {
        return navigator.clipboard.writeText(text).catch(() => {
          return this.legacyCopy(text)
        })
      } else {
        return Promise.resolve(this.legacyCopy(text))
      }
    },
    legacyCopy(text) {
      return new Promise((resolve, reject) => {
        const textarea = document.createElement('textarea')
        textarea.value = text
        textarea.style.position = 'fixed'
        textarea.style.opacity = '0'
        document.body.appendChild(textarea)
        textarea.select()
        try {
          const success = document.execCommand('copy')
          document.body.removeChild(textarea)
          if (success) {
            resolve()
          } else {
            reject(new Error('复制失败'))
          }
        } catch (error) {
          document.body.removeChild(textarea)
          reject(error)
        }
      })
    },
    handleMarkerCardClick(marker) {
      this.$emit('marker-clicked', {
        type: marker.type,
        id: marker.data.id,
        data: marker.data
      })
    },
    handleTaskCreated(taskData) {
      // Emit event to refresh timeline and stats
      this.$emit('task-created', taskData)
      // Optionally refresh markers if needed
      // this.loadAllMarkers()
    },
    getEventStatusLabel(status) {
      const statusMap = {
        draft: '草稿',
        pending: '待处理',
        processing: '处理中',
        completed: '已完成',
        archived: '已归档'
      }
      return statusMap[status] || status || '未知'
    },
    highlightMarker(markerId) {
      const mapInstance = this.$refs.mainMap && this.$refs.mainMap.map
      if (!markerId || !mapInstance) return
      const marker = this.allMarkers.find(item => item.id === markerId)
      if (marker) {
        const lng = Number(marker.lng)
        const lat = Number(marker.lat)
        if (!isNaN(lng) && !isNaN(lat)) {
          const position = [lng, lat]
          const targetZoom = Math.max(this.mapZoom, 14)
          this.mapCenter = position
          this.mapZoom = targetZoom
          this.$nextTick(() => {
            try {
              mapInstance.setZoomAndCenter(targetZoom, position)
            } catch (e) {
              console.warn('高亮标记失败:', e)
            }
          })
        }
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.dispatch-map-container {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}

.map-wrapper {
  flex: 1;
  min-height: 0;
  position: relative;
}

.marker-panel {
  flex: 0 0 220px;
  background: rgba(255, 255, 255, 0.95);
  border-radius: 8px;
  padding: 12px;
  margin-top: 16px;
  color: #303133;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.marker-panel h4 {
  margin: 0 0 8px;
  font-size: 14px;
  font-weight: 600;
}

.marker-scroll {
  flex: 1;
  overflow-y: auto;
  min-height: 0;
}

.marker-card {
  background: rgba(255, 255, 255, 0.9);
  border-radius: 8px;
  padding: 12px;
  margin-bottom: 8px;
  color: #303133;
  cursor: pointer;
  transition: background 0.2s;
  
  &:hover {
    background: #f5f7fa;
  }
  
  &:last-child {
    margin-bottom: 0;
  }
}

.marker-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}

.marker-type {
  color: #fff;
  padding: 2px 6px;
  border-radius: 999px;
  font-size: 12px;
  white-space: nowrap;
}

.marker-body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 13px;
  color: #606266;
}
</style>

