<!--监测报警一张图-->
<template>
  <div class="gis-alert-dashboard">
    <!-- 顶部状态栏 -->
    <div class="top-bar">

      <div class="alert-stats">
        <div class="stat" @click="focusLayer('critical')">
          <span class="stat-value critical">{{ criticalCount }}</span>
          <span class="stat-label">严重报警</span>
        </div>
        <div class="stat" @click="focusLayer('warning')">
          <span class="stat-value warning">{{ warningCount }}</span>
          <span class="stat-label">一般报警</span>
        </div>
        <div class="stat" @click="focusLayer('normal')">
          <span class="stat-value">{{ normalCount }}</span>
          <span class="stat-label">正常井盖</span>
        </div>
        <div class="stat" @click="focusLayer('offline')">
          <span class="stat-value offline">{{ offlineCount }}</span>
          <span class="stat-label">离线设备</span>
        </div>
      </div>
    </div>

    <div class="main-layout">
      <!-- 左侧图层控制面板 -->
      <div class="layer-control">
        <div class="layer-header">
          <el-icon><Monitor /></el-icon> 态势图层
        </div>
        <div class="layer-filter-panel">
          <el-input
            v-model="queryParams.keyword"
            clearable
            :prefix-icon="Search"
            placeholder="设备编号/名称/位置模糊查询"
            @keyup.enter="handleSearch"
          />
          <div class="filter-actions">
            <el-button type="primary" size="small" @click="handleSearch">查询</el-button>
            <el-button size="small" :icon="RefreshRight" @click="handleReset">重置</el-button>
          </div>
          <div class="filter-summary">
            <el-tag size="small" effect="plain">搜索结果 {{ totalDevices }} 台</el-tag>
            <el-tag size="small" type="success" effect="plain">当前显示 {{ displayDevices.length }} 台</el-tag>
            <el-tag v-if="activeQuickFilter" size="small" type="warning" effect="plain">态势筛选: {{ quickFilterLabel }}</el-tag>
          </div>
        </div>
        <el-tree
            ref="layerTreeRef"
            :data="layerTreeData"
            show-checkbox
            check-strictly
            node-key="id"
            :default-checked-keys="checkedKeys"
            :default-expand-all="true"
            @check="onLayerChange"
            class="layer-tree"
        >
          <template #default="{ node, data }">
            <span class="layer-node">
              <el-icon v-if="data.icon"><component :is="data.icon" /></el-icon>
              <span>{{ node.label }}</span>
              <el-badge v-if="data.alertCount" :value="data.alertCount" type="danger" class="layer-badge" />
            </span>
          </template>
        </el-tree>
        <div class="legend-panel">
          <div class="legend-title">图例说明</div>
          <div><span class="legend-marker critical-dot"></span> 严重报警</div>
          <div><span class="legend-marker warning-dot"></span> 一般报警</div>
          <div><span class="legend-marker normal-dot"></span> 正常在线</div>
          <div><span class="legend-marker offline-dot"></span> 离线/停用</div>
          <div><span class="legend-marker alarm-pulse"></span> 实时报警闪烁</div>
        </div>
        <div class="time-selector">
          <el-date-picker v-model="timeRange" type="datetimerange" range-separator="至" size="small" :shortcuts="shortcuts" start-placeholder="开始" end-placeholder="结束" />
        </div>
        <div class="panel-tip">已选图层会实时过滤地图点位，支持结合关键字一起查询。</div>
      </div>

      <!-- 右侧GIS地图核心区 -->
      <div class="gis-map-area">
        <div class="map-toolbar">
          <el-button-group>
            <el-button size="small" :icon="ZoomIn" @click="zoomIn">放大</el-button>
            <el-button size="small" :icon="ZoomOut" @click="zoomOut">缩小</el-button>
            <el-button size="small" :icon="FullScreen" @click="resetView">重置视图</el-button>
          </el-button-group>
          <div class="current-stat">
            <span><el-icon><Position /></el-icon> 设备总数: {{ totalDevices }}</span>
            <span><el-icon><Monitor /></el-icon> 当前显示: {{ displayDevices.length }}</span>
            <span class="alert-summary">报警中: {{ totalActiveAlerts }}</span>
          </div>
        </div>
        <div class="map-container" ref="mapContainer" v-loading="listLoading">
          <div ref="baiduMapRef" class="baidu-map"></div>
          <div v-if="!listLoading && !displayDevices.length" class="empty-state">
            当前筛选条件下暂无设备
          </div>
          <div v-if="mapError" class="map-error">
            {{ mapError }}
          </div>
        </div>
        <!-- 右下角报警聚合弹窗/详情 -->
        <el-drawer v-model="drawerVisible" :title="selectedDevice?.name + ' - 监测报警详情'" direction="rtl" size="420px">
          <div v-if="selectedDevice" v-loading="detailLoading">
            <el-descriptions :column="1" border>
              <el-descriptions-item label="设备编号">{{ selectedDevice.deviceCode || '—' }}</el-descriptions-item>
              <el-descriptions-item label="地理位置">{{ selectedDevice.address }}</el-descriptions-item>
              <el-descriptions-item label="当前状态">
                <el-tag :type="getStatusTag(selectedDevice.status)">{{ selectedDevice.statusText }}</el-tag>
              </el-descriptions-item>
              <el-descriptions-item label="报警级别" v-if="selectedDevice.hasAlert">
                <el-tag :type="selectedDevice.level === 'critical' ? 'danger' : 'warning'">{{ selectedDevice.level === 'critical' ? '严重报警' : '一般报警' }}</el-tag>
              </el-descriptions-item>
              <el-descriptions-item label="报警类型">{{ selectedDevice.alertType || '无' }}</el-descriptions-item>
              <el-descriptions-item label="实时监测值">{{ selectedDevice.realTimeValue || '—' }}</el-descriptions-item>
              <el-descriptions-item label="报警阈值">{{ selectedDevice.threshold || '—' }}</el-descriptions-item>
              <el-descriptions-item label="最近通讯">{{ selectedDevice.lastComm }}</el-descriptions-item>
            </el-descriptions>
            <el-divider>处置建议</el-divider>
            <div class="advice-box">
              <p>{{ getAlertAdvice(selectedDevice) }}</p>
              <el-button type="primary" size="small" style="margin-top: 12px;" @click="dispatchWorkOrder">派发处置工单</el-button>
            </div>
            <el-divider v-if="selectedDevice.alertLogs?.length">报警记录</el-divider>
            <el-timeline>
              <el-timeline-item v-for="log in selectedDevice.alertLogs" :key="log.time" :timestamp="log.time" type="danger">
                {{ log.content }}
              </el-timeline-item>
            </el-timeline>
          </div>
        </el-drawer>
      </div>
    </div>
  </div>
</template>

<script setup>
import {computed, nextTick, onMounted, onUnmounted, ref, watch} from 'vue'
import {
  Connection,
  FullScreen,
  InfoFilled,
  Monitor,
  Position,
  RefreshRight,
  Search,
  Setting,
  WarningFilled,
  ZoomIn,
  ZoomOut
} from '@element-plus/icons-vue'
import {ElMessage} from 'element-plus'
import {getManholeAlarmDeviceDetail, getManholeAlarmDeviceList, getManholeLayerData} from '@/api/pipeNetwork/basic'

// 树复选框默认勾选全部状态
const DEFAULT_CHECKED_KEYS = ['current-1', 'current-3', 'alarm-1', 'alarm-0', 'online-1', 'online-0']
const checkedKeys = ref([...DEFAULT_CHECKED_KEYS])
const visibleLayers = ref(new Set(DEFAULT_CHECKED_KEYS))
const layerTreeRef = ref(null)

// 动态生成树数据（包括设备级子节点），每次 displayDevices 变化自动重算
const layerTreeData = computed(() => {
  const devices = displayDevices.value
  const total = devices.length
  const critical = devices.filter(m => m.status === 'critical').length
  const warning = devices.filter(m => m.status === 'warning').length
  const normal = devices.filter(m => m.status === 'normal').length
  const offline = devices.filter(m => m.status === 'offline').length
  const inUse = devices.filter(item => Number(item.raw?.equipmentStatus?.currentStatus) === 1).length
  const maintenance = devices.filter(item => Number(item.raw?.equipmentStatus?.currentStatus) === 3).length

  function buildDeviceNode(device) {
    const typeId = Number(device.raw?.equipmentTypeId)
    const typeName = typeId === 5 ? '供水窨井' : typeId === 9 ? '排水窨井' : typeId === 10 ? '燃气窨井' : (device.equipmentTypeName || '未知类型')
    const code = device.deviceCode || device.id || ''
    return {
      id: `device-${device.equipmentId}`,
      label: `${typeName}-${code}`,
      disabled: true
    }
  }

  return [
    {
      id: 'current-status',
      label: '运维状态筛选',
      icon: Setting,
      alertCount: inUse + maintenance,
      disabled: true,
      children: [
        { id: 'current-1', label: '在用设备', icon: Monitor, alertCount: inUse,
          children: devices.filter(d => Number(d.raw?.equipmentStatus?.currentStatus) === 1).map(buildDeviceNode) },
        { id: 'current-3', label: '维修设备', icon: Setting, alertCount: maintenance,
          children: devices.filter(d => Number(d.raw?.equipmentStatus?.currentStatus) === 3).map(buildDeviceNode) }
      ]
    },
    {
      id: 'alarm-status',
      label: '报警状态筛选',
      icon: WarningFilled,
      alertCount: critical + warning + normal,
      disabled: true,
      children: [
        { id: 'alarm-1', label: '报警设备', icon: WarningFilled, alertCount: critical + warning,
          children: devices.filter(d => d.status === 'critical' || d.status === 'warning').map(buildDeviceNode) },
        { id: 'alarm-0', label: '正常设备', icon: InfoFilled, alertCount: normal,
          children: devices.filter(d => d.status === 'normal').map(buildDeviceNode) }
      ]
    },
    {
      id: 'online-status',
      label: '在线状态筛选',
      icon: Connection,
      alertCount: total,
      disabled: true,
      children: [
        { id: 'online-1', label: '在线设备', icon: Connection, alertCount: total - offline,
          children: devices.filter(d => d.status !== 'offline').map(buildDeviceNode) },
        { id: 'online-0', label: '离线设备', icon: Connection, alertCount: offline,
          children: devices.filter(d => d.status === 'offline').map(buildDeviceNode) }
      ]
    }
  ]
})
const queryParams = ref({
  keyword: ''
})
const mockManholes = ref([])
const listLoading = ref(false)
const detailLoading = ref(false)
const activeQuickFilter = ref('')
const baiduMapRef = ref(null)
const mapError = ref('')

const BAIDU_MAP_AK = import.meta.env.VITE_BAIDU_MAP_AK || ''
const DEFAULT_MAP_CENTER = { lng: 110.393, lat: 28.452 }

let mapInstance = null
let mapOverlays = []
let baiduMapScriptPromise = null

const quickFilterLabelMap = {
  critical: '严重报警',
  warning: '一般报警',
  normal: '正常井盖',
  offline: '离线设备'
}

const quickFilterLabel = computed(() => quickFilterLabelMap[activeQuickFilter.value] || '')

function isBatteryLow(device) {
  const battery = toNumber(device.battery)
  return battery !== null && battery <= 20
}

function matchesQuickFilter(device) {
  if (!activeQuickFilter.value) return true
  return device.status === activeQuickFilter.value
}

/**
 * 图层树勾选过滤：根据 visibleLayers 判断设备是否应显示
 * - 无状态记录的设备视为离线（onlineStatus=0）
 * - 某分类全部勾选时等同于不过滤（兼容无状态记录的设备）
 */
function matchesLayerFilter(device) {
  const keys = visibleLayers.value
  // 没有勾选任何状态时显示全部
  if (keys.size === 0) return true

  const st = device.raw?.equipmentStatus || {}
  const currentStatus = Number(st.currentStatus)
  const alarmStatus = Number(st.alarmStatus)
  const onlineStatus = Number(st.onlineStatus)
  const hasNoStatus = !device.raw?.equipmentStatus

  // OR 逻辑：匹配任意一个勾选状态即显示
  if (keys.has('current-1') && currentStatus === 1) return true
  if (keys.has('current-3') && currentStatus === 3) return true
  if (keys.has('alarm-1') && alarmStatus === 1) return true
  if (keys.has('alarm-0') && alarmStatus === 0) return true
  if (keys.has('online-1') && onlineStatus === 1) return true
  if (keys.has('online-0') && (onlineStatus === 0 || hasNoStatus)) return true

  return false
}

const displayDevices = computed(() => {
  return mockManholes.value.filter(device => {
    // 图层树过滤
    if (!matchesLayerFilter(device)) return false
    // 顶部统计栏快速过滤
    if (!matchesQuickFilter(device)) return false
    return true
  })
})

const criticalCount = computed(() => displayDevices.value.filter(m => m.status === 'critical').length)
const warningCount = computed(() => displayDevices.value.filter(m => m.status === 'warning').length)
const normalCount = computed(() => displayDevices.value.filter(m => m.status === 'normal').length)
const offlineCount = computed(() => displayDevices.value.filter(m => m.status === 'offline').length)
const totalDevices = computed(() => mockManholes.value.length)
const totalActiveAlerts = computed(() => criticalCount.value + warningCount.value)

const mapContainer = ref(null)
const bounds = ref({ minLng: 121.45, maxLng: 121.55, minLat: 31.22, maxLat: 31.28 })

function toNumber(value) {
  const num = Number(value)
  return Number.isFinite(num) ? num : null
}

function formatDateTime(value) {
  return value || '—'
}

function isValidCoordinate(lng, lat) {
  return lng !== null && lat !== null && lng >= 70 && lng <= 140 && lat >= 3 && lat <= 55
}

function getThresholdTextByCode(raw, warningCode) {
  const list = Array.isArray(raw?.warningThresholdList) ? raw.warningThresholdList : []
  const target = list.find(item => item.warningCode === warningCode)
  if (!target) return '—'
  const { minValue, maxValue } = target
  if (minValue !== null && minValue !== undefined && maxValue !== null && maxValue !== undefined) {
    return `${minValue} ~ ${maxValue}`
  }
  if (minValue !== null && minValue !== undefined) return `<= ${minValue}`
  if (maxValue !== null && maxValue !== undefined) return `>= ${maxValue}`
  return '—'
}

function buildAlertInfo(raw) {
  const status = raw?.equipmentStatus || {}
  const manholeData = raw?.manholeData || {}
  const battery = toNumber(manholeData.batteryLevel)
  const signal = toNumber(manholeData.signalStrength)
  const tiltAngle = manholeData?.tiltAngle

  if (Number(status.onlineStatus) !== 1) {
    return { status: 'offline', statusText: '离线', hasAlert: false, level: '', alertType: '', realTimeValue: '—', threshold: '—' }
  }

  if (`${manholeData.waterLevelAlarmStatus}` === '1') {
    return {
      status: 'critical',
      statusText: '严重报警',
      hasAlert: true,
      level: 'critical',
      alertType: '水位报警',
      realTimeValue: '报警',
      threshold: getThresholdTextByCode(raw, 'WARN-WATER-LEVEL')
    }
  }

  if (`${manholeData.waterInfiltrationAlarmStatus}` === '1') {
    return {
      status: 'critical',
      statusText: '严重报警',
      hasAlert: true,
      level: 'critical',
      alertType: '水浸报警',
      realTimeValue: '报警',
      threshold: getThresholdTextByCode(raw, 'WARN-WATER-INFILTRATION')
    }
  }

  if (Number(status.alarmStatus) === 1) {
    return {
      status: 'critical',
      statusText: '严重报警',
      hasAlert: true,
      level: 'critical',
      alertType: tiltAngle ? '倾斜报警' : '设备报警',
      realTimeValue: tiltAngle ? `${tiltAngle}°` : '报警',
      threshold: tiltAngle ? getThresholdTextByCode(raw, 'WARN-TILT') : getThresholdTextByCode(raw, 'WARN-DEVICE-ALARM')
    }
  }

  if ((battery !== null && battery <= 20) || (signal !== null && signal <= 20)) {
    return {
      status: 'warning',
      statusText: '一般报警',
      hasAlert: true,
      level: 'warning',
      alertType: battery !== null && battery <= 20 ? '低电量预警' : '弱信号预警',
      realTimeValue: battery !== null && battery <= 20 ? `${battery}%` : `${signal}%`,
      threshold: '20'
    }
  }

  return { status: 'normal', statusText: '正常', hasAlert: false, level: '', alertType: '', realTimeValue: '—', threshold: '—' }
}

function buildAlertLogs(raw, alertInfo) {
  if (!alertInfo?.hasAlert) return []
  const timestamp = raw?.equipmentStatus?.statusUpdateTime || raw?.updateTime || raw?.installTime || ''
  return [{
    time: formatDateTime(timestamp),
    content: `${alertInfo.alertType}${alertInfo.realTimeValue && alertInfo.realTimeValue !== '—' ? `：${alertInfo.realTimeValue}` : ''}${alertInfo.threshold && alertInfo.threshold !== '—' ? `，阈值 ${alertInfo.threshold}` : ''}`
  }]
}

function normalizeDevice(raw, _index = 0, baseDevice = {}) {
  const rawLng = toNumber(raw?.longitude)
  const rawLat = toNumber(raw?.latitude)
  const baseLng = toNumber(baseDevice.lng)
  const baseLat = toNumber(baseDevice.lat)
  const useRawCoordinate = isValidCoordinate(rawLng, rawLat)
  const useBaseCoordinate = isValidCoordinate(baseLng, baseLat)
  const lng = useRawCoordinate ? rawLng : (useBaseCoordinate ? baseLng : null)
  const lat = useRawCoordinate ? rawLat : (useBaseCoordinate ? baseLat : null)
  const alertInfo = buildAlertInfo(raw)
  const address = raw?.equipmentLocation || baseDevice.address || '暂无位置信息'
  return {
    equipmentId: raw?.equipmentId || baseDevice.equipmentId || '',
    id: raw?.equipmentCode || baseDevice.id || raw?.equipmentId || '',
    deviceCode: raw?.equipmentCode || baseDevice.deviceCode || '',
    name: raw?.equipmentName || baseDevice.name || raw?.equipmentCode || '未命名设备',
    lng,
    lat,
    address,
    status: alertInfo.status,
    statusText: alertInfo.statusText,
    hasAlert: alertInfo.hasAlert,
    level: alertInfo.level,
    alertType: alertInfo.alertType,
    realTimeValue: alertInfo.realTimeValue,
    threshold: alertInfo.threshold,
    lastComm: formatDateTime(raw?.equipmentStatus?.statusUpdateTime || raw?.updateTime || raw?.installTime),
    locationShort: address.length > 8 ? `${address.slice(0, 8)}...` : address,
    battery: raw?.manholeData?.batteryLevel || '—',
    alertLogs: buildAlertLogs(raw, alertInfo),
    equipmentTypeName: raw?.equipmentTypeName || '—',
    equipmentModel: raw?.equipmentModel || '—',
    manufacturer: raw?.manufacturer || '—',
    installTime: formatDateTime(raw?.installTime),
    maintainer: raw?.maintainer || '—',
    raw
  }
}

function refreshLayerTree() {
  // 已废弃：树数据由 layerTreeData computed 自动生成
}

function refreshBounds() {
  const validList = displayDevices.value.filter(item => Number.isFinite(item.lng) && Number.isFinite(item.lat))
  if (!validList.length) {
    bounds.value = { minLng: 110.35, maxLng: 110.43, minLat: 28.42, maxLat: 28.5 }
    return
  }
  const lngList = validList.map(item => item.lng)
  const latList = validList.map(item => item.lat)
  const minLng = Math.min(...lngList)
  const maxLng = Math.max(...lngList)
  const minLat = Math.min(...latList)
  const maxLat = Math.max(...latList)
  bounds.value = {
    minLng: minLng - 0.01,
    maxLng: maxLng + 0.01,
    minLat: minLat - 0.01,
    maxLat: maxLat + 0.01
  }
}

function getStatusColor(status) {
  if (status === 'critical') return '#f56c6c'
  if (status === 'warning') return '#e6a23c'
  if (status === 'offline') return '#909399'
  return '#67c23a'
}

function getMarkerHtml(device, isActive = false) {
  const color = getStatusColor(device.status)
  const pulse = device.status === 'critical'
    ? 'box-shadow: 0 0 0 8px rgba(245,108,108,0.18);'
    : ''
  const activeRing = isActive
    ? 'border: 3px solid #ffffff; transform: scale(1.08);'
    : 'border: 2px solid #ffffff;'
  return `
    <div style="display:flex;flex-direction:column;align-items:center;transform:translateY(-6px);cursor:pointer;">
      <div style="max-width:160px;padding:4px 8px;border-radius:999px;background:rgba(20,33,61,0.82);color:#fff;font-size:12px;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-bottom:6px;">
        ${device.name}
      </div>
      <div style="width:18px;height:18px;border-radius:50%;background:${color};${activeRing}${pulse}"></div>
    </div>
  `
}

function clearMapOverlays() {
  if (!mapInstance) return
  mapOverlays.forEach((overlay) => {
    try {
      mapInstance.removeOverlay(overlay)
    } catch (_) {}
  })
  mapOverlays = []
}

function fitMapViewport() {
  if (!mapInstance || !window.BMapGL) return
  if (!displayDevices.value.length) {
    mapInstance.centerAndZoom(new window.BMapGL.Point(DEFAULT_MAP_CENTER.lng, DEFAULT_MAP_CENTER.lat), 14)
    return
  }
  const points = displayDevices.value
    .filter(device => isValidCoordinate(device.lng, device.lat))
    .map(device => new window.BMapGL.Point(device.lng, device.lat))
  if (!points.length) {
    mapInstance.centerAndZoom(new window.BMapGL.Point(DEFAULT_MAP_CENTER.lng, DEFAULT_MAP_CENTER.lat), 14)
    return
  }
  mapInstance.setViewport(points)
  if (mapInstance.getZoom() > 16) {
    mapInstance.setZoom(16)
  }
  if (mapInstance.getZoom() < 12) {
    mapInstance.setZoom(12)
  }
}

function renderMapOverlays() {
  if (!mapInstance || !window.BMapGL) return
  console.log('[renderMapOverlays] 准备渲染的设备:', displayDevices.value.length)
  clearMapOverlays()
  const validDevices = displayDevices.value.filter(device => isValidCoordinate(device.lng, device.lat))
  console.log('[renderMapOverlays] 有效坐标设备:', validDevices.length)
  console.log('[renderMapOverlays] 无效坐标设备:', displayDevices.value.filter(d => !isValidCoordinate(d.lng, d.lat)).map(d => ({ id: d.id, lng: d.lng, lat: d.lat })))
  
  validDevices.forEach((device) => {
    console.log('[renderMapOverlays] 渲染点位:', device.name, 'lng:', device.lng, 'lat:', device.lat)
    const point = new window.BMapGL.Point(device.lng, device.lat)
    const isActive = selectedDevice.value?.equipmentId === device.equipmentId
    const label = new window.BMapGL.Label(getMarkerHtml(device, isActive), {
      position: point,
      offset: new window.BMapGL.Size(-30, -52)
    })
    label.setStyle({
      border: 'none',
      background: 'transparent',
      padding: '0'
    })
    label.addEventListener('click', async (event) => {
      event?.domEvent?.stopPropagation?.()
      await openDeviceDetail(device)
    })
    mapInstance.addOverlay(label)
    mapOverlays.push(label)
  })
  fitMapViewport()
}

let _renderTimer = null
function renderMap() {
  if (!mapInstance || !window.BMapGL) return
  if (_renderTimer) clearTimeout(_renderTimer)
  _renderTimer = setTimeout(() => {
    renderMapOverlays()
    _renderTimer = null
  }, 50)
}

function ensureBaiduMap() {
  if (window.BMapGL) {
    return Promise.resolve(window.BMapGL)
  }
  if (baiduMapScriptPromise) {
    return baiduMapScriptPromise
  }
  if (!BAIDU_MAP_AK) {
    return Promise.reject(new Error('未配置百度地图 AK，请在 .env.development 中配置 VITE_BAIDU_MAP_AK'))
  }

  baiduMapScriptPromise = new Promise((resolve, reject) => {
    const existing = document.querySelector('script[data-baidu-map="webgl"]')
    if (existing) {
      let attempts = 0
      const timer = window.setInterval(() => {
        attempts++
        if (window.BMapGL) {
          window.clearInterval(timer)
          resolve(window.BMapGL)
        } else if (attempts >= 50) {
          window.clearInterval(timer)
          reject(new Error('百度地图脚本加载超时'))
        }
      }, 200)
      return
    }

    const script = document.createElement('script')
    script.src = `https://api.map.baidu.com/api?type=webgl&v=1.0&ak=${BAIDU_MAP_AK}`
    script.async = true
    script.defer = true
    script.setAttribute('data-baidu-map', 'webgl')
    script.onload = () => {
      let attempts = 0
      const timer = window.setInterval(() => {
        attempts++
        if (window.BMapGL) {
          window.clearInterval(timer)
          resolve(window.BMapGL)
        } else if (attempts >= 50) {
          window.clearInterval(timer)
          reject(new Error('百度地图脚本初始化超时'))
        }
      }, 200)
    }
    script.onerror = () => reject(new Error('百度地图脚本加载失败'))
    document.head.appendChild(script)
  })

  return baiduMapScriptPromise
}

async function initMap() {
  if (!baiduMapRef.value) return
  try {
    await ensureBaiduMap()
    if (!mapInstance) {
      mapInstance = new window.BMapGL.Map(baiduMapRef.value, { enableMapClick: true })
      mapInstance.enableScrollWheelZoom(true)
      mapInstance.setMinZoom(11)
      mapInstance.setMaxZoom(18)
      mapInstance.centerAndZoom(new window.BMapGL.Point(DEFAULT_MAP_CENTER.lng, DEFAULT_MAP_CENTER.lat), 14)
      mapInstance.addEventListener('click', () => {
        drawerVisible.value = false
      })
    }
    mapError.value = ''
    renderMap()
  } catch (error) {
    mapError.value = error?.message || '百度地图加载失败'
  }
}

async function loadDeviceList() {
  listLoading.value = true
  try {
    const keyword = queryParams.value.keyword?.trim()
    
    // 只传 keyword 和 isQueryManholeData，不传状态筛选
    // 树勾选过滤在 displayDevices computed 中做前端过滤
    const res = await getManholeLayerData({
      keyword: keyword || undefined,
      isQueryManholeData: true
    })
    
    const result = res.data || {}
    mockManholes.value = (result.devices || []).map((item, index) => normalizeDevice(item, index))
    
    // 同步统计信息
    const stats = result.statistics || {}
    console.log('[alarmSanalysis] 后端统计数据:', stats)
    
    // displayDevices computed 和 watch 自动触发树、地图刷新
  } catch (error) {
    mockManholes.value = []
    const msg = error?.message || error?.msg || '未知错误'
    console.error('[alarmSanalysis] 加载失败:', error)
    ElMessage.error('井盖设备数据加载失败: ' + msg)
  } finally {
    listLoading.value = false
  }
}

async function openDeviceDetail(device) {
  if (!device?.equipmentId) return
  selectedDevice.value = device
  drawerVisible.value = true
  detailLoading.value = true
  try {
    const res = await getManholeAlarmDeviceDetail(device.equipmentId)
    if (res?.data) {
      const index = mockManholes.value.findIndex(item => item.equipmentId === device.equipmentId)
      selectedDevice.value = normalizeDevice(res.data, index, device)
      if (mapInstance && window.BMapGL && isValidCoordinate(selectedDevice.value.lng, selectedDevice.value.lat)) {
        mapInstance.panTo(new window.BMapGL.Point(selectedDevice.value.lng, selectedDevice.value.lat))
      }
      renderMap()
    }
  } catch (error) {
    ElMessage.error('设备详情加载失败')
  } finally {
    detailLoading.value = false
  }
}

function zoomIn() {
  if (!mapInstance) return
  mapInstance.setZoom(Math.min(mapInstance.getZoom() + 1, 18))
}
function zoomOut() {
  if (!mapInstance) return
  mapInstance.setZoom(Math.max(mapInstance.getZoom() - 1, 11))
}
function resetView() {
  if (!mapInstance || !window.BMapGL) return
  fitMapViewport()
}

const onLayerChange = (_data, checkedInfo) => {
  // check-strictly 模式下 checkedKeys 只含叶子节点，仅需排除 device-*
  const statusKeys = checkedInfo.checkedKeys.filter(key => !key.startsWith('device-'))
  const newSet = new Set(statusKeys)
  const oldSet = visibleLayers.value
  // 值未变时跳过，阻断 setCheckedKeys → onLayerChange → watch 循环
  if (newSet.size === oldSet.size && [...newSet].every(k => oldSet.has(k))) return
  visibleLayers.value = newSet
  checkedKeys.value = statusKeys
}
const focusLayer = async (type) => {
  activeQuickFilter.value = activeQuickFilter.value === type ? '' : type
  const target = displayDevices.value.find(item => item.status === type)
  if (!target) {
    if (activeQuickFilter.value) {
      ElMessage.info('当前筛选下无对应设备')
    }
    return
  }
  if (!activeQuickFilter.value) {
    ElMessage.info('当前无对应设备')
    return
  }
  await nextTick()
  renderMap()
}

const selectedDevice = ref(null)
const drawerVisible = ref(false)
const timeRange = ref([])
const shortcuts = [{ text: '最近24小时', value: () => [new Date(Date.now() - 86400000), new Date()] }]

const getStatusTag = (status) => {
  if (status === 'critical') return 'danger'
  if (status === 'warning') return 'warning'
  if (status === 'offline') return 'info'
  return 'success'
}
const getAlertAdvice = (device) => {
  if (device.alertType?.includes('倾斜')) return '建议立即安排检修人员现场确认井盖固定情况，如损坏需更换。'
  if (device.alertType?.includes('水位')) return '井内水位过高，需紧急排水，检查管道是否堵塞。'
  if (device.alertType?.includes('水浸')) return '建议核查井内积水和周边排水情况，必要时安排现场排查。'
  if (device.alertType?.includes('低电量')) return '建议尽快安排电池更换，避免设备掉线。'
  if (device.alertType?.includes('弱信号')) return '建议核查设备天线、网络覆盖和安装环境。'
  return '请根据现场情况迅速核实并处置。'
}
const dispatchWorkOrder = () => { ElMessage.success('已派发工单至维护班组') }

function handleSearch() {
  activeQuickFilter.value = ''
  loadDeviceList()
}

function handleReset() {
  queryParams.value.keyword = ''
  activeQuickFilter.value = ''
  visibleLayers.value = new Set(DEFAULT_CHECKED_KEYS)
  checkedKeys.value = [...DEFAULT_CHECKED_KEYS]
  loadDeviceList()
}

watch(displayDevices, async () => {
  refreshBounds()
  await nextTick()
  // 树数据变化后 el-tree 内部状态被重置，用 setCheckedKeys 恢复勾选
  layerTreeRef.value?.setCheckedKeys(checkedKeys.value)
  renderMap()
}, { deep: true })

onMounted(async () => {
  await nextTick()
  await initMap()
  await loadDeviceList()
  // renderMap 由 watch(displayDevices) 自动触发，避免重复渲染
  window.addEventListener('resize', renderMap)
})
onUnmounted(() => {
  window.removeEventListener('resize', renderMap)
  clearMapOverlays()
  mapInstance = null
})
</script>

<style scoped>
.gis-alert-dashboard {
  background: #eef2f0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.top-bar {
  background: white;
  padding: 10px 24px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  box-shadow: 0 2px 10px rgba(0,0,0,0.05);
}
.logo-area { display: flex; align-items: center; gap: 14px; }
.title { font-size: 1.5rem; font-weight: 700; background: linear-gradient(135deg, #1e5128, #409eff); -webkit-background-clip: text; background-clip: text; color: transparent; }
.alert-stats { display: flex; gap: 24px; }
.stat { text-align: center; cursor: pointer; padding: 4px 16px; border-radius: 40px; transition: 0.2s; }
.stat:hover { background: #f0f2f5; }
.stat-value { font-size: 26px; font-weight: bold; display: block; line-height: 1.2; }
.stat-value.critical { color: #f56c6c; }
.stat-value.warning { color: #e6a23c; }
.stat-value.offline { color: #909399; }
.stat-label { font-size: 12px; color: #606266; }
.main-layout { display: flex; flex: 1; gap: 16px; padding: 16px; overflow: hidden; }
.layer-control {
  width: 280px;
  background: white;
  border-radius: 20px;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  overflow-y: auto;
}
.layer-header { font-weight: bold; display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }
.layer-filter-panel {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.filter-actions {
  display: flex;
  gap: 8px;
}
.filter-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.layer-tree { flex: 1; }
.layer-badge { margin-left: auto; }
.legend-panel { border-top: 1px solid #e9ecef; padding-top: 12px; margin-top: 8px; }
.legend-title { margin-bottom: 8px; font-weight: 500; font-size: 13px; }
.legend-marker { display: inline-block; width: 14px; height: 14px; border-radius: 14px; margin-right: 8px; vertical-align: middle; }
.critical-dot { background: #f56c6c; box-shadow: 0 0 0 2px rgba(245,108,108,0.4); }
.warning-dot { background: #e6a23c; }
.normal-dot { background: #67c23a; }
.offline-dot { background: #909399; }
.alarm-pulse { width: 14px; height: 14px; background: red; border-radius: 50%; animation: pulse 1s infinite; display: inline-block; margin-right: 8px; }
@keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.4; transform: scale(1.2); } 100% { opacity: 1; } }
.gis-map-area {
  flex: 1;
  background: white;
  border-radius: 20px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.map-toolbar {
  padding: 12px 16px;
  border-bottom: 1px solid #edf2f0;
  display: flex;
  justify-content: space-between;
}
.current-stat { display: flex; gap: 20px; font-size: 13px; }
.map-container {
  flex: 1;
  position: relative;
  overflow: hidden;
}
.baidu-map {
  width: 100%;
  height: 100%;
}
.empty-state {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  color: #909399;
  font-size: 14px;
  background: rgba(255, 255, 255, 0.92);
  padding: 10px 18px;
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  z-index: 2;
}
.map-error {
  position: absolute;
  top: 16px;
  right: 16px;
  max-width: 320px;
  color: #f56c6c;
  background: rgba(255, 255, 255, 0.95);
  border: 1px solid rgba(245, 108, 108, 0.25);
  border-radius: 12px;
  padding: 10px 12px;
  font-size: 12px;
  line-height: 1.6;
  z-index: 3;
}
.advice-box { background: #f8f9fa; padding: 12px; border-radius: 12px; }
.panel-tip {
  font-size: 12px;
  color: #909399;
  line-height: 1.5;
}
</style>
