<!--状态监测报警-->
<!--监测报警一张图-->
<template>
  <div class="alert-dashboard">
    <!-- 头部统计告警栏 -->
    <div class="alert-header">

      <div class="stats-cards">
        <div class="stat-item" :class="{ active: filterType === 'all' }" @click="filterAlerts('all')">
          <div class="stat-num">{{ totalAlerts }}</div>
          <div class="stat-label">全部报警</div>
        </div>
        <div class="stat-item critical" :class="{ active: filterType === 'critical' }" @click="filterAlerts('critical')">
          <div class="stat-num">{{ criticalCount }}</div>
          <div class="stat-label">严重报警</div>
        </div>
        <div class="stat-item warning" :class="{ active: filterType === 'warning' }" @click="filterAlerts('warning')">
          <div class="stat-num">{{ warningCount }}</div>
          <div class="stat-label">一般报警</div>
        </div>
      </div>
    </div>

    <!-- 主内容区域：左侧报警列表 + 右侧详情研判 -->
    <div class="main-content">
      <!-- 左侧报警列表 -->
      <div class="alert-list-panel" v-loading="listLoading">
        <div class="panel-header">
          <span>报警事件列表 <el-badge :value="unhandledCount" class="badge" /></span>
          <el-input v-model="searchText" placeholder="搜索位置/设备编号" prefix-icon="Search" clearable size="small" style="width: 180px" />
        </div>
        <div class="alert-list">
          <div
              v-for="alert in filteredAlerts"
              :key="alert.id"
              class="alert-item"
              :class="{
              selected: selectedAlert?.id === alert.id,
              critical: alert.level === 'critical',
              warning: alert.level === 'warning'
            }"
              @click="selectAlert(alert)"
          >
            <div class="alert-level-icon">
              <el-icon v-if="alert.level === 'critical'"><WarningFilled /></el-icon>
              <el-icon v-else-if="alert.level === 'warning'"><InfoFilled /></el-icon>
              <el-icon v-else><CircleCheck /></el-icon>
            </div>
            <div class="alert-content">
              <div class="alert-title">
                <span>{{ alert.deviceName }}</span>
                <span class="alert-time">{{ alert.time }}</span>
              </div>
              <div class="alert-location">
                <el-icon><Location /></el-icon> {{ alert.location }}
              </div>
              <div class="alert-type">{{ alert.alertType }}</div>
              <div class="alert-value" v-if="alert.exceedValue">实时值: <strong class="exceed">{{ alert.exceedValue }}</strong> (阈值: {{ alert.threshold }})</div>
            </div>
            <div class="alert-status" v-if="alert.status === 'resolved'">
              <el-tag type="success" size="small">已处置</el-tag>
            </div>
            <div class="alert-status" v-else-if="alert.status === 'processing'">
              <el-tag type="warning" size="small">处理中</el-tag>
            </div>
            <div class="alert-status" v-else>
              <el-tag type="danger" size="small">待处理</el-tag>
            </div>
          </div>
          <el-empty v-if="!filteredAlerts.length && !listLoading" description="暂无报警事件" :image-size="100" />
        </div>
      </div>

      <!-- 右侧报警详情与研判面板 -->
      <div class="detail-panel" v-if="selectedAlert" v-loading="detailLoading">
        <!-- 报警基本信息 -->
        <div class="detail-section">
          <div class="section-title">
            <span><el-icon><Warning /></el-icon> 报警详情 - 辅助研判</span>
          </div>
          <el-descriptions :column="2" border>
            <el-descriptions-item label="报警位置">
              <strong>{{ selectedAlert.location }}</strong> <el-button link type="primary" size="small" @click="viewOnMap">查看地图</el-button>
            </el-descriptions-item>
            <el-descriptions-item label="报警级别">
              <el-tag :type="selectedAlert.level === 'critical' ? 'danger' : 'warning'" size="default">
                {{ selectedAlert.level === 'critical' ? '严重报警' : '一般报警' }}
              </el-tag>
            </el-descriptions-item>
            <el-descriptions-item label="设备编号">{{ selectedAlert.deviceId }}</el-descriptions-item>
            <el-descriptions-item label="设备类型">{{ selectedAlert.deviceType }}</el-descriptions-item>
            <el-descriptions-item label="报警类型">{{ selectedAlert.alertType }}</el-descriptions-item>
            <el-descriptions-item label="报警时间">{{ selectedAlert.time }}</el-descriptions-item>
            <el-descriptions-item label="实时数据" :span="2">
              <div class="real-time-data">
                <span v-if="selectedAlert.realData">
                  当前 {{ selectedAlert.alertParam }} = <strong class="warning-value">{{ selectedAlert.realData }}</strong>
                  (阈值: {{ selectedAlert.threshold }})
                </span>
                <span v-else>{{ selectedAlert.exceedValue || '超出阈值' }}</span>
              </div>
            </el-descriptions-item>
          </el-descriptions>
        </div>
      </div>

      <!-- 未选中报警时的空状态 -->
      <div v-else class="empty-detail">
        <el-empty description="请从左侧选择一个报警事件进行研判" :image-size="140" />
      </div>
    </div>

    <!-- 地图弹窗 -->
    <el-dialog v-model="mapDialogVisible" title="报警位置地图" width="720px" @opened="handleMapDialogOpened">
      <div class="dialog-map-wrapper">
        <div ref="dialogMapRef" class="dialog-baidu-map"></div>
        <div v-if="dialogMapError" class="dialog-map-error">{{ dialogMapError }}</div>
        <div v-if="!hasAlertCoordinate" class="dialog-map-empty">
          当前报警缺少真实坐标，已展示默认地图视野
        </div>
        <div class="dialog-map-footer">
          <div><strong>{{ selectedAlert?.location || '暂无位置' }}</strong></div>
          <div>经度: {{ selectedAlert?.lng || '暂无数据' }}, 纬度: {{ selectedAlert?.lat || '暂无数据' }}</div>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script setup>
import {computed, nextTick, onMounted, onUnmounted, ref, watch} from 'vue'
import {CircleCheck, InfoFilled, Location, Warning, WarningFilled} from '@element-plus/icons-vue'
import {ElMessage} from 'element-plus'
import {getManholeAlarmDeviceDetail, getManholeAlarmDeviceList} from '@/api/pipeNetwork/basic'

const alerts = ref([])
const searchText = ref('')
const filterType = ref('all')
const selectedAlert = ref(null)
const mapDialogVisible = ref(false)
const listLoading = ref(false)
const detailLoading = ref(false)
const dialogMapRef = ref(null)
const dialogMapError = ref('')

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

let dialogMapInstance = null
let dialogMapOverlays = []
let baiduMapScriptPromise = null

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

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

function formatDateTime(value) {
  if (!value) return '—'
  return String(value).replace('T', ' ')
}

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 = toNumber(manholeData.tiltAngle)

  if (`${manholeData.waterLevelAlarmStatus}` === '1') {
    return {
      hasAlert: true,
      level: 'critical',
      levelText: '严重报警',
      alertType: '水位报警',
      alertParam: '水位',
      realData: manholeData.waterLevel !== undefined && manholeData.waterLevel !== null ? `${manholeData.waterLevel}cm` : '报警',
      threshold: getThresholdTextByCode(raw, 'WARN-WATER-LEVEL')
    }
  }

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

  if (Number(status.alarmStatus) === 1) {
    return {
      hasAlert: true,
      level: 'critical',
      levelText: '严重报警',
      alertType: tiltAngle !== null ? '倾斜报警' : '设备报警',
      alertParam: tiltAngle !== null ? '倾斜角' : '设备状态',
      realData: tiltAngle !== null ? `${tiltAngle}°` : '报警',
      threshold: tiltAngle !== null ? getThresholdTextByCode(raw, 'WARN-TILT') : '—'
    }
  }

  if (battery !== null && battery <= 20) {
    return {
      hasAlert: true,
      level: 'warning',
      levelText: '一般报警',
      alertType: '低电量预警',
      alertParam: '电池电量',
      realData: `${battery}%`,
      threshold: '20%'
    }
  }

  if (signal !== null && signal <= 20) {
    return {
      hasAlert: true,
      level: 'warning',
      levelText: '一般报警',
      alertType: '弱信号预警',
      alertParam: '信号强度',
      realData: `${signal}%`,
      threshold: '20%'
    }
  }

  return {
    hasAlert: false,
    level: '',
    levelText: '',
    alertType: '',
    alertParam: '',
    realData: '',
    threshold: '—'
  }
}

function normalizeAlert(raw, baseAlert = null) {
  const alertInfo = buildAlertInfo(raw)
  if (!alertInfo.hasAlert) return null
  return {
    id: raw?.equipmentId || raw?.equipmentCode,
    equipmentId: raw?.equipmentId || '',
    deviceId: raw?.equipmentCode || raw?.equipmentId || '—',
    deviceName: raw?.equipmentName || raw?.equipmentCode || '未命名设备',
    deviceType: raw?.equipmentTypeName || '井盖监测设备',
    location: raw?.equipmentLocation || '暂无位置信息',
    lng: raw?.longitude || baseAlert?.lng || '',
    lat: raw?.latitude || baseAlert?.lat || '',
    alertType: alertInfo.alertType,
    alertParam: alertInfo.alertParam,
    realData: alertInfo.realData,
    threshold: alertInfo.threshold,
    exceedValue: alertInfo.realData || '报警',
    level: alertInfo.level,
    levelText: alertInfo.levelText,
    time: formatDateTime(raw?.equipmentStatus?.statusUpdateTime || raw?.updateTime || raw?.installTime),
    status: raw?.equipmentStatus?.alarmStatus === 1 ? 'pending' : 'resolved',
    statusText: raw?.equipmentStatus?.alarmStatus === 1 ? '待处理' : '已恢复',
    raw
  }
}

async function loadAlerts() {
  listLoading.value = true
  try {
    const res = await getManholeAlarmDeviceList({
      alarmStatus: 1,
      isQueryManholeData: true
    })
    const list = Array.isArray(res?.data) ? res.data : []
    alerts.value = list
      .map(item => normalizeAlert(item))
      .filter(Boolean)
    if (!alerts.value.length) {
      selectedAlert.value = null
      return
    }
    const currentId = selectedAlert.value?.id
    selectedAlert.value = alerts.value.find(item => item.id === currentId) || alerts.value[0]
    if (selectedAlert.value?.equipmentId) {
      await loadAlertDetail(selectedAlert.value)
    }
  } catch (error) {
    alerts.value = []
    selectedAlert.value = null
    ElMessage.error('报警设备加载失败')
  } finally {
    listLoading.value = false
  }
}

async function loadAlertDetail(alert) {
  if (!alert?.equipmentId) return
  detailLoading.value = true
  try {
    const res = await getManholeAlarmDeviceDetail(alert.equipmentId)
    if (res?.data) {
      const merged = normalizeAlert(res.data, alert)
      if (merged) {
        const idx = alerts.value.findIndex(item => item.id === merged.id)
        if (idx > -1) {
          alerts.value[idx] = merged
        }
        selectedAlert.value = merged
      }
    }
  } catch (error) {
    ElMessage.error('报警详情加载失败')
  } finally {
    detailLoading.value = false
  }
}

const filteredAlerts = computed(() => {
  let list = alerts.value
  if (filterType.value === 'critical') {
    list = list.filter(a => a.level === 'critical')
  } else if (filterType.value === 'warning') {
    list = list.filter(a => a.level === 'warning')
  }

  if (searchText.value) {
    const kw = searchText.value.toLowerCase()
    list = list.filter(a =>
      `${a.location || ''}`.toLowerCase().includes(kw) ||
      `${a.deviceId || ''}`.toLowerCase().includes(kw) ||
      `${a.deviceName || ''}`.toLowerCase().includes(kw)
    )
  }
  return list
})

const totalAlerts = computed(() => alerts.value.length)
const criticalCount = computed(() => alerts.value.filter(a => a.level === 'critical').length)
const warningCount = computed(() => alerts.value.filter(a => a.level === 'warning').length)
const unhandledCount = computed(() => alerts.value.length)
const hasAlertCoordinate = computed(() => isValidCoordinate(toNumber(selectedAlert.value?.lng), toNumber(selectedAlert.value?.lat)))

const filterAlerts = (type) => {
  filterType.value = type
}

const selectAlert = async (alert) => {
  selectedAlert.value = alert
  await loadAlertDetail(alert)
}

const viewOnMap = () => {
  mapDialogVisible.value = true
}

function clearDialogMapMarker() {
  if (!dialogMapInstance || !dialogMapOverlays.length) return
  dialogMapOverlays.forEach((overlay) => {
    try {
      dialogMapInstance.removeOverlay(overlay)
    } catch (_) {}
  })
  dialogMapOverlays = []
}

function getDialogInfoWindowHtml() {
  const levelTagColor = selectedAlert.value?.level === 'critical' ? '#f56c6c' : '#e6a23c'
  const levelText = selectedAlert.value?.levelText || '报警'
  return `
    <div style="min-width:220px;max-width:280px;padding:4px 2px;line-height:1.7;color:#303133;">
      <div style="font-size:14px;font-weight:700;color:#1f2937;margin-bottom:6px;">
        ${selectedAlert.value?.deviceName || '报警设备'}
      </div>
      <div style="margin-bottom:4px;">
        <span style="display:inline-block;padding:1px 8px;border-radius:999px;background:${levelTagColor};color:#fff;font-size:12px;">
          ${levelText}
        </span>
      </div>
      <div style="font-size:12px;"><span style="color:#909399;">报警类型：</span>${selectedAlert.value?.alertType || '—'}</div>
      <div style="font-size:12px;"><span style="color:#909399;">报警时间：</span>${selectedAlert.value?.time || '—'}</div>
      <div style="font-size:12px;"><span style="color:#909399;">实时数据：</span>${selectedAlert.value?.realData || selectedAlert.value?.exceedValue || '—'}</div>
      <div style="font-size:12px;"><span style="color:#909399;">阈值：</span>${selectedAlert.value?.threshold || '—'}</div>
      <div style="font-size:12px;"><span style="color:#909399;">报警位置：</span>${selectedAlert.value?.location || '—'}</div>
    </div>
  `
}

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
}

function renderDialogMapMarker() {
  if (!dialogMapInstance || !window.BMapGL) return
  clearDialogMapMarker()

  const lng = toNumber(selectedAlert.value?.lng)
  const lat = toNumber(selectedAlert.value?.lat)
  if (!isValidCoordinate(lng, lat)) {
    dialogMapInstance.centerAndZoom(new window.BMapGL.Point(DEFAULT_MAP_CENTER.lng, DEFAULT_MAP_CENTER.lat), 13)
    return
  }

  const point = new window.BMapGL.Point(lng, lat)
  dialogMapInstance.centerAndZoom(point, 15)
  const marker = new window.BMapGL.Marker(point)
  const infoWindow = new window.BMapGL.InfoWindow(getDialogInfoWindowHtml(), {
    width: 260,
    title: '报警信息'
  })
  dialogMapInstance.addOverlay(marker)
  dialogMapOverlays.push(marker)
  marker.addEventListener('click', () => {
    dialogMapInstance.openInfoWindow(infoWindow, point)
  })

  const label = new window.BMapGL.Label(
    `<div style="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;">${selectedAlert.value?.deviceName || '报警设备'}</div>`,
    {
      position: point,
      offset: new window.BMapGL.Size(-30, -40)
    }
  )
  label.setStyle({
    border: 'none',
    background: 'transparent',
    padding: '0'
  })
  label.addEventListener('click', () => {
    dialogMapInstance.openInfoWindow(infoWindow, point)
  })
  dialogMapInstance.addOverlay(label)
  dialogMapOverlays.push(label)
  dialogMapInstance.openInfoWindow(infoWindow, point)
}

async function initDialogMap() {
  if (!dialogMapRef.value) return
  try {
    await ensureBaiduMap()
    if (!dialogMapInstance) {
      dialogMapInstance = new window.BMapGL.Map(dialogMapRef.value, { enableMapClick: true })
      dialogMapInstance.enableScrollWheelZoom(true)
      dialogMapInstance.centerAndZoom(new window.BMapGL.Point(DEFAULT_MAP_CENTER.lng, DEFAULT_MAP_CENTER.lat), 13)
    }
    dialogMapError.value = ''
    renderDialogMapMarker()
  } catch (error) {
    dialogMapError.value = error?.message || '百度地图加载失败'
  }
}

async function handleMapDialogOpened() {
  await nextTick()
  await initDialogMap()
}

watch(
  () => selectedAlert.value?.id,
  async () => {
    if (!mapDialogVisible.value) return
    await nextTick()
    renderDialogMapMarker()
  }
)

onMounted(async () => {
  await loadAlerts()
})

onUnmounted(() => {
  clearDialogMapMarker()
  dialogMapInstance = null
})
</script>

<style scoped>
.alert-dashboard {
  background: #f0f2f6;
  min-height: 100vh;
  padding: 20px;
}
.alert-header {
  background: white;
  border-radius: 20px;
  padding: 16px 24px;
  margin-bottom: 20px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.04);
}
.title-badge {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 16px;
}
.blink-icon {
  font-size: 28px;
  color: #f56c6c;
  animation: blink 1s infinite;
}
@keyframes blink { 0% { opacity: 1; } 50% { opacity: 0.4; } 100% { opacity: 1; } }
.title { font-size: 22px; font-weight: 700; }
.stats-cards { display: flex; gap: 20px; margin-top: 6px; }
.stat-item { background: #f8fafc; padding: 10px 24px; border-radius: 16px; cursor: pointer; text-align: center; transition: all 0.2s; min-width: 100px; }
.stat-item.active { background: #ecf5ff; border: 1px solid #409eff; }
.stat-num { font-size: 28px; font-weight: bold; }
.stat-item.critical .stat-num { color: #f56c6c; }
.stat-item.warning .stat-num { color: #e6a23c; }
.main-content { display: flex; gap: 20px; }
.alert-list-panel {
  width: 400px;
  background: white;
  border-radius: 20px;
  padding: 16px;
  display: flex;
  flex-direction: column;
}
.panel-header { display: flex; justify-content: space-between; margin-bottom: 16px; font-weight: 600; }
.alert-list { max-height: calc(100vh - 200px); overflow-y: auto; }
.alert-item {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 14px;
  margin-bottom: 12px;
  border-radius: 14px;
  background: #fafbfc;
  cursor: pointer;
  border: 1px solid #e9ecef;
  transition: all 0.2s;
}
.alert-item.selected { background: #ecf5ff; border-color: #409eff; }
.alert-item.critical { border-left: 4px solid #f56c6c; }
.alert-item.warning { border-left: 4px solid #e6a23c; }
.alert-level-icon { font-size: 22px; margin-top: 4px; }
.alert-content { flex: 1; }
.alert-title { display: flex; justify-content: space-between; font-weight: 600; margin-bottom: 4px; }
.alert-time { font-size: 11px; color: #909399; }
.alert-location { font-size: 12px; color: #606266; display: flex; align-items: center; gap: 4px; margin: 4px 0; }
.alert-type { font-size: 12px; color: #409eff; }
.alert-value { font-size: 12px; margin-top: 6px; }
.exceed { color: #f56c6c; }
.detail-panel {
  flex: 1;
  background: white;
  border-radius: 20px;
  padding: 20px;
  overflow-y: auto;
  max-height: calc(100vh - 150px);
}
.detail-section {
  margin-bottom: 24px;
  border-bottom: 1px solid #f0f0f0;
  padding-bottom: 20px;
}
.section-title {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
  font-weight: 600;
  font-size: 16px;
}
.real-time-data { background: #fff9f0; padding: 8px; border-radius: 8px; }
.warning-value { color: #f56c6c; font-size: 18px; margin: 0 4px; }
.action-buttons { display: flex; gap: 8px; }
.empty-detail { flex: 1; display: flex; align-items: center; justify-content: center; background: white; border-radius: 20px; }
.dialog-map-wrapper {
  position: relative;
}
.dialog-baidu-map {
  height: 420px;
  border-radius: 12px;
  overflow: hidden;
  background: #eef2f0;
}
.dialog-map-footer {
  padding-top: 12px;
  font-size: 13px;
  color: #606266;
  line-height: 1.8;
}
.dialog-map-empty {
  position: absolute;
  top: 16px;
  left: 16px;
  background: rgba(255, 255, 255, 0.94);
  color: #909399;
  font-size: 12px;
  padding: 8px 12px;
  border-radius: 10px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  z-index: 2;
}
.dialog-map-error {
  position: absolute;
  top: 16px;
  right: 16px;
  max-width: 280px;
  background: rgba(255, 255, 255, 0.95);
  color: #f56c6c;
  border: 1px solid rgba(245, 108, 108, 0.25);
  border-radius: 10px;
  padding: 8px 12px;
  font-size: 12px;
  line-height: 1.6;
  z-index: 2;
}
</style>
