<template>
  <div class="gis-dashboard">
    <div class="dashboard-header">
      <div class="header-title">
        <div class="title-main">
          <el-icon><MapLocation /></el-icon>
          <span>燃气管网GIS一张图</span>
        </div>
        <div class="title-metrics">
          <span class="metric metric-danger">管线 {{ summaryStats.pipelineLength }}km</span>
          <span class="metric metric-primary">燃气管点 {{ summaryStats.pipePointCount }}个</span>
          <span class="metric metric-warning">窨井 {{ summaryStats.manholeCount }}个</span>
        </div>
      </div>
      <div class="header-actions">
        <el-input
          v-model="searchKeyword"
          class="search-input"
          placeholder="搜索管点/井盖编号/位置"
          clearable
          @keyup.enter="handleSearch"
        >
          <template #prefix>
            <el-icon><Search /></el-icon>
          </template>
        </el-input>
        <el-button type="primary" @click="handleSearch">
          <el-icon><Search /></el-icon>
          搜索
        </el-button>
        <el-button @click="refreshScene">
          <el-icon><RefreshRight /></el-icon>
          刷新
        </el-button>
        <el-button @click="toggleFullscreen">
          <el-icon><FullScreen /></el-icon>
          全图
        </el-button>
      </div>
    </div>

    <div ref="screenRef" class="dashboard-content">
      <aside class="dashboard-sidebar">
        <el-card shadow="never" class="panel-card">
          <template #header>
            <span>图层控制</span>
          </template>
          <div class="layer-group">
            <div class="layer-title">燃气管线</div>
            <el-checkbox v-model="layerState.pipelines.high">高压管线</el-checkbox>
            <el-checkbox v-model="layerState.pipelines.subHigh">次高压管线</el-checkbox>
            <el-checkbox v-model="layerState.pipelines.medium">中压管线</el-checkbox>
            <el-checkbox v-model="layerState.pipelines.low">低压管线</el-checkbox>
          </div>
          <div class="layer-group">
            <div class="layer-title">燃气管点</div>
            <el-checkbox v-model="layerState.pipePoints.valve">阀门</el-checkbox>
            <el-checkbox v-model="layerState.pipePoints.regulator">调压器</el-checkbox>
            <el-checkbox v-model="layerState.pipePoints.flowmeter">流量计</el-checkbox>
            <el-checkbox v-model="layerState.pipePoints.terminal">终端节点</el-checkbox>
          </div>
          <div class="layer-group layer-group-last">
            <div class="layer-title">窨井设施</div>
            <el-checkbox v-model="layerState.manholes.cover">窨井盖</el-checkbox>
            <el-checkbox v-model="layerState.manholes.inspection">检查井</el-checkbox>
          </div>
        </el-card>

        <el-card shadow="never" class="panel-card">
          <template #header>
            <span>图例说明</span>
          </template>
          <div class="legend-list">
            <div class="legend-item"><span class="legend-line legend-high"></span><span>高压管线</span></div>
            <div class="legend-item"><span class="legend-line legend-sub-high"></span><span>次高压管线</span></div>
            <div class="legend-item"><span class="legend-line legend-medium"></span><span>中压管线</span></div>
            <div class="legend-item"><span class="legend-line legend-low"></span><span>低压管线</span></div>
            <div class="legend-item"><span class="legend-dot legend-valve"></span><span>阀门</span></div>
            <div class="legend-item"><span class="legend-dot legend-regulator"></span><span>调压器</span></div>
            <div class="legend-item"><span class="legend-dot legend-flowmeter"></span><span>流量计</span></div>
            <div class="legend-item"><span class="legend-dot legend-terminal"></span><span>终端节点</span></div>
            <div class="legend-item"><span class="legend-square legend-cover"></span><span>窨井盖</span></div>
            <div class="legend-item"><span class="legend-square legend-inspection"></span><span>检查井</span></div>
          </div>
        </el-card>

        <el-card shadow="never" class="panel-card stats-card">
          <template #header>
            <span>测绘数据统计</span>
          </template>
          <div class="stats-list">
            <div class="stats-row"><span>管线总长</span><strong>{{ summaryStats.pipelineLength }} km</strong></div>
            <div class="stats-row"><span>管点总数</span><strong>{{ summaryStats.pipePointCount }}</strong></div>
            <div class="stats-row"><span>窨井总数</span><strong>{{ summaryStats.manholeCount }}</strong></div>
            <div class="stats-row"><span>覆盖面积</span><strong>{{ summaryStats.coverageArea }} km²</strong></div>
          </div>
        </el-card>

        <el-card shadow="never" class="panel-card detail-card">
          <template #header>
            <span>要素详情</span>
          </template>
          <div v-if="selectedFeature" class="detail-body">
            <div class="detail-name">{{ selectedFeature.name }}</div>
            <div class="detail-tag">{{ selectedFeature.category }}</div>
            <el-descriptions :column="1" border size="small">
              <el-descriptions-item
                v-for="item in selectedFeatureDetails"
                :key="item.label"
                :label="item.label"
              >
                {{ item.value }}
              </el-descriptions-item>
            </el-descriptions>
          </div>
          <el-empty v-else description="点击地图要素查看详情" :image-size="72" />
        </el-card>
      </aside>

      <section class="dashboard-map-panel">
        <div class="map-toolbar">
          <div class="toolbar-left">
            <el-button @click="zoomIn">
              <el-icon><Plus /></el-icon>
              放大
            </el-button>
            <el-button @click="zoomOut">
              <el-icon><Minus /></el-icon>
              缩小
            </el-button>
            <el-button @click="locateCenter">
              <el-icon><Location /></el-icon>
              定位
            </el-button>
          </div>
          <div class="toolbar-right">当前坐标: {{ currentCoordinate }}</div>
        </div>
        <div id="gisMap" ref="mapRef" class="gis-map"></div>
        <div v-if="mapError" class="map-error">{{ mapError }}</div>
      </section>
    </div>
  </div>
</template>

<script setup>
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'
import { FullScreen, Location, MapLocation, Minus, Plus, RefreshRight, Search } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { convertCoord } from '@/utils/coordTransform'
import { getPipeNetworkOptions, getGasPipePointPage, getManholeList } from '@/api/pipeNetwork/basic'

const centerPoint = { lng: 110.386, lat: 28.445 }

const MAP_BOUNDS = {
  southWest: { lng: 110.355, lat: 28.428 },
  northEast: { lng: 110.410, lat: 28.460 }
}
const MAP_MIN_ZOOM = 13
const MAP_MAX_ZOOM = 19
const MAP_DEFAULT_ZOOM = 15

const defaultLayerState = () => ({
  pipelines: { high: true, subHigh: true, medium: true, low: true },
  pipePoints: { valve: true, regulator: true, flowmeter: true, terminal: true },
  manholes: { cover: true, inspection: true }
})

const boundaryPoints = [
  { lng: 110.358, lat: 28.456 },
  { lng: 110.375, lat: 28.458 },
  { lng: 110.392, lat: 28.458 },
  { lng: 110.408, lat: 28.455 },
  { lng: 110.410, lat: 28.448 },
  { lng: 110.407, lat: 28.440 },
  { lng: 110.400, lat: 28.436 },
  { lng: 110.390, lat: 28.434 },
  { lng: 110.378, lat: 28.433 },
  { lng: 110.368, lat: 28.436 },
  { lng: 110.360, lat: 28.445 }
]

const pipelineData = [
  {
    id: 'pipe-high-01', level: 'high', name: '燃气1', code: 'GX-HP-001', length: 4.1,
    material: 'L290N 无缝钢管', diameter: 'DN300', pressure: '高压A (4.0MPa)', road: '燃气1主干线',
    status: '运行正常', layingMethod: '直埋敷设', depth: '1.8m', commissioningDate: '2026-06',
    points: [{lng:110.404947,lat:28.433419},{lng:110.404836,lat:28.433429},{lng:110.403275,lat:28.433571},{lng:110.401084,lat:28.433876},{lng:110.399601,lat:28.433876},{lng:110.398112,lat:28.433979},{lng:110.396717,lat:28.434314},{lng:110.394299,lat:28.434538},{lng:110.394352,lat:28.434887},{lng:110.391969,lat:28.434985},{lng:110.384374,lat:28.435695},{lng:110.381418,lat:28.43559},{lng:110.377993,lat:28.436193},{lng:110.376062,lat:28.436385},{lng:110.374231,lat:28.43655},{lng:110.372584,lat:28.437107},{lng:110.371292,lat:28.4377},{lng:110.370581,lat:28.438198},{lng:110.369831,lat:28.438821}]
  },
  {
    id: 'pipe-subhigh-01', level: 'subHigh', name: '燃气2', code: 'GX-SHP-002', length: 3.8,
    material: 'L245N 无缝钢管', diameter: 'DN250', pressure: '次高压A (1.6MPa)', road: '燃气2支线',
    status: '运行正常', layingMethod: '直埋敷设', depth: '1.6m', commissioningDate: '2026-03',
    points: [{lng:110.361433,lat:28.454979},{lng:110.362363,lat:28.453169},{lng:110.362851,lat:28.452213},{lng:110.364377,lat:28.452443},{lng:110.365138,lat:28.45246},{lng:110.366462,lat:28.452157},{lng:110.369549,lat:28.451441},{lng:110.37219,lat:28.450897},{lng:110.372753,lat:28.450901},{lng:110.373875,lat:28.451194},{lng:110.373913,lat:28.451107},{lng:110.374597,lat:28.451476}]
  }
]

const pipePointData = ref([])
const manholeData = ref([])

async function loadGisData() {
  try {
    const [pointRes, manholeRes] = await Promise.all([
      getGasPipePointPage(1, 500, {}),
      getManholeList()
    ])
    const points = (pointRes.data && pointRes.data.records) ? pointRes.data.records : []
    pipePointData.value = points.filter(p => p.longitude && p.latitude).map(p => ({
      id: 'point-' + p.pointId, type: mapPointType(p.pointType), pipelineId: p.networkId,
      name: p.pointName, code: p.pointCode, road: p.networkName || '', status: '在线',
      deviceModel: p.material || '', caliber: p.diameter ? p.diameter + 'mm' : '',
      lng: Number(p.longitude), lat: Number(p.latitude)
    }))
    const manholes = manholeRes.data || []
    manholeData.value = manholes.filter(m => m.longitude && m.latitude).map(m => ({
      id: 'manhole-' + m.manholeId, type: 'cover', pipelineId: m.networkId || '',
      name: m.manholeName, code: m.manholeCode, road: '', status: m.status === '0' ? '完好' : '异常',
      material: m.material || '', size: m.manholeShape || '', lng: Number(m.longitude), lat: Number(m.latitude)
    }))
    if (mapInstance && typeof BMapGL !== 'undefined') renderMapScene()
  } catch (e) { console.error(e) }
}

function mapPointType(type) {
  if (!type) return 'terminal'
  if (type.includes('阀门') || type === 'valve') return 'valve'
  if (type.includes('调压') || type === 'regulator') return 'regulator'
  if (type.includes('计量') || type.includes('流量') || type === 'flowmeter') return 'flowmeter'
  return 'terminal'
}

const colorMap = {
  high: '#e63946',
  subHigh: '#f77f00',
  medium: '#fcbf49',
  low: '#2a9d8f',
  valve: '#457b9d',
  regulator: '#e76f51',
  flowmeter: '#2d6a4f',
  terminal: '#6c757d',
  cover: '#7f4f24',
  inspection: '#b08968'
}

const labelMap = {
  high: '高压管线',
  subHigh: '次高压管线',
  medium: '中压管线',
  low: '低压管线',
  valve: '阀门',
  regulator: '调压器',
  flowmeter: '流量计',
  terminal: '终端节点',
  cover: '窨井盖',
  inspection: '检查井'
}

const mapRef = ref(null)
const screenRef = ref(null)
const searchKeyword = ref('')
const currentCoordinate = ref(`${centerPoint.lng}, ${centerPoint.lat}`)
const selectedFeature = ref(null)
const mapError = ref('')
const layerState = reactive(defaultLayerState())

let mapInstance = null
let activeInfoWindow = null
let overlayClicked = false

const summaryStats = computed(() => ({
  pipelineLength: pipelineData.reduce((sum, item) => sum + item.length, 0).toFixed(1),
  pipePointCount: pipePointData.value.length,
  manholeCount: manholeData.value.length,
  coverageArea: '18.6'
}))

const selectedFeatureDetails = computed(() => {
  if (!selectedFeature.value) return []
  return Object.entries(selectedFeature.value.details).map(([label, value]) => ({ label, value }))
})

const searchableFeatures = computed(() => {
  const pipelines = pipelineData.map(item => ({
    kind: 'pipeline',
    type: item.level,
    name: item.name,
    code: item.code,
    road: item.road,
    lng: getMidPoint(item.points).lng,
    lat: getMidPoint(item.points).lat,
    raw: item
  }))
  const pipePoints = pipePointData.value.map(item => ({
    kind: 'pipePoint',
    type: item.type,
    name: item.name,
    code: item.code,
    road: item.road,
    lng: item.lng,
    lat: item.lat,
    raw: item
  }))
  const manholes = manholeData.value.map(item => ({
    kind: 'manhole',
    type: item.type,
    name: item.name,
    code: item.code,
    road: item.road,
    lng: item.lng,
    lat: item.lat,
    raw: item
  }))
  return [...pipelines, ...pipePoints, ...manholes]
})

watch(layerState, () => {
  renderMapScene()
}, { deep: true })

onMounted(async () => {
  await nextTick()
  await loadGisData()
  waitForBMapGL()
  document.addEventListener('fullscreenchange', handleFullscreenChange)
})

onBeforeUnmount(() => {
  document.removeEventListener('fullscreenchange', handleFullscreenChange)
  if (mapInstance) {
    mapInstance.clearOverlays()
    mapInstance = null
  }
})

function waitForBMapGL() {
  if (typeof BMapGL !== 'undefined') {
    initMap()
    return
  }

  let attempts = 0
  const maxAttempts = 50
  const timer = setInterval(() => {
    attempts++
    if (typeof BMapGL !== 'undefined') {
      clearInterval(timer)
      initMap()
      return
    }
    if (attempts >= maxAttempts) {
      clearInterval(timer)
      mapError.value = '百度地图脚本加载超时，请刷新页面重试。'
    }
  }, 200)
}

function initMap() {
  const el = document.getElementById('gisMap')
  if (!el) {
    mapError.value = '地图容器未找到。'
    return
  }

  try {
    mapInstance = new BMapGL.Map('gisMap', { enableMapClick: true })
  } catch (e) {
    console.error('创建地图实例失败：', e)
    mapError.value = '百度地图初始化失败，请检查AK和网络连接。'
    return
  }

  try {
    const [clng, clat] = convertCoord(centerPoint.lng, centerPoint.lat)
    const centerBMapPoint = new BMapGL.Point(clng, clat)
    mapInstance.centerAndZoom(centerBMapPoint, MAP_DEFAULT_ZOOM)
    mapInstance.enableScrollWheelZoom(true)
  } catch (e) {
    console.error('设置地图中心失败：', e)
  }

  try {
    if (typeof mapInstance.setMinZoom === 'function') {
      mapInstance.setMinZoom(MAP_MIN_ZOOM)
    }
    if (typeof mapInstance.setMaxZoom === 'function') {
      mapInstance.setMaxZoom(MAP_MAX_ZOOM)
    }
  } catch (e) {
    console.warn('设置缩放限制失败：', e)
  }

  try {
    if (typeof mapInstance.setMaxBounds === 'function') {
      const sw = new BMapGL.Point(MAP_BOUNDS.southWest.lng, MAP_BOUNDS.southWest.lat)
      const ne = new BMapGL.Point(MAP_BOUNDS.northEast.lng, MAP_BOUNDS.northEast.lat)
      mapInstance.setMaxBounds(new BMapGL.Bounds(sw, ne))
    }
  } catch (e) {
    console.warn('设置地图范围限制失败：', e)
  }

  mapInstance.addEventListener('click', () => {
    if (overlayClicked) {
      overlayClicked = false
      return
    }
    closeInfoWindow()
    selectedFeature.value = null
  })

  mapInstance.addEventListener('mousemove', (event) => {
    try {
      if (event && event.latlng) {
        currentCoordinate.value = `${event.latlng.lng.toFixed(4)}, ${event.latlng.lat.toFixed(4)}`
      }
    } catch (_) { /* ignore mousemove errors */ }
  })

  try {
    renderMapScene()
  } catch (e) {
    console.error('渲染地图要素失败：', e)
    mapError.value = '地图要素渲染失败。'
  }
}

function renderMapScene() {
  if (!mapInstance || typeof BMapGL === 'undefined') return

  closeInfoWindow()
  try { mapInstance.clearOverlays() } catch (_) { /* ignore */ }
  try { drawPipelines() } catch (e) { console.warn('绘制管线失败：', e) }
  try { drawPipePoints() } catch (e) { console.warn('绘制管点失败：', e) }
  try { drawManholes() } catch (e) { console.warn('绘制窨井失败：', e) }
}

function drawBoundary() {
  const pts = boundaryPoints.map(item => { const [lng, lat] = convertCoord(item.lng, item.lat); return new BMapGL.Point(lng, lat) })
  const polygon = new BMapGL.Polygon(pts, {
    strokeColor: '#52b788',
    strokeWeight: 2.5,
    strokeOpacity: 0.85,
    strokeStyle: 'dashed',
    fillColor: '#d8f3dc',
    fillOpacity: 0.22
  })
  mapInstance.addOverlay(polygon)
}

function drawPipelines() {
  pipelineData.forEach(item => {
    try {
      if (!layerState.pipelines[item.level]) return
      const pts = item.points.map(p => { const [lng, lat] = convertCoord(p.lng, p.lat); return new BMapGL.Point(lng, lat) })
      const polyline = new BMapGL.Polyline(pts, {
        strokeColor: colorMap[item.level],
        strokeWeight: 6,
        strokeOpacity: 0.92
      })
      const firstPt = { lng: convertCoord(item.points[0].lng, item.points[0].lat)[0], lat: convertCoord(item.points[0].lng, item.points[0].lat)[1] }
      try {
        polyline.addEventListener('click', (e) => {
          overlayClicked = true
          e.domEvent && e.domEvent.stopPropagation && e.domEvent.stopPropagation()
          showPopup(firstPt.lng, firstPt.lat, buildPopupHTML(buildPipelineDetail(item)))
          selectedFeature.value = buildPipelineDetail(item)
        })
      } catch (_) { /* polyline click listener failed */ }
      mapInstance.addOverlay(polyline)

      const rawMid = getMidPoint(item.points)
      const mid = { lng: convertCoord(rawMid.lng, rawMid.lat)[0], lat: convertCoord(rawMid.lng, rawMid.lat)[1] }
      addPipeLabel(mid.lng, mid.lat, item.name, colorMap[item.level], item)
    } catch (e) {
      console.warn(`绘制管线 ${item.name} 失败：`, e)
    }
  })
}

function drawPipePoints() {
  pipePointData.value.forEach(item => {
    try {
      if (!layerState.pipePoints[item.type]) return
      const [plng, plat] = convertCoord(item.lng, item.lat)
      addPointMarker(plng, plat, colorMap[item.type], item.name, 'dot', () => {
        showPopup(plng, plat, buildPopupHTML(buildPipePointDetail(item)))
        selectedFeature.value = buildPipePointDetail(item)
      })
    } catch (e) {
      console.warn(`绘制管点 ${item.name} 失败：`, e)
    }
  })
}

function drawManholes() {
  manholeData.value.forEach(item => {
    try {
      if (!layerState.manholes[item.type]) return
      const [mlng, mlat] = convertCoord(item.lng, item.lat)
      addPointMarker(mlng, mlat, colorMap[item.type], item.name, 'square', () => {
        showPopup(mlng, mlat, buildPopupHTML(buildManholeDetail(item)))
        selectedFeature.value = buildManholeDetail(item)
      })
    } catch (e) {
      console.warn(`绘制窨井 ${item.name} 失败：`, e)
    }
  })
}

function addPipeLabel(lng, lat, text, color, rawItem) {
  const point = new BMapGL.Point(lng, lat)
  const html = `<div class="pipe-label" style="color:${color}">${text}</div>`
  const label = new BMapGL.Label(html, {
    position: point,
    offset: new BMapGL.Size(-28, -8)
  })
  label.setStyle({ border: 'none', background: 'transparent', padding: '0' })
  try {
    label.addEventListener('click', (e) => {
      overlayClicked = true
      e.domEvent && e.domEvent.stopPropagation && e.domEvent.stopPropagation()
      showPopup(lng, lat, buildPopupHTML(buildPipelineDetail(rawItem)))
      selectedFeature.value = buildPipelineDetail(rawItem)
    })
  } catch (_) { /* label click listener failed */ }
  mapInstance.addOverlay(label)
}

function addPointMarker(lng, lat, color, name, shape, onClick) {
  const point = new BMapGL.Point(lng, lat)
  const size = 22
  const borderRadius = shape === 'square' ? '3px' : '50%'
  const html = `<div class="marker-wrap" style="cursor:pointer">
    <div style="width:${size}px;height:${size}px;background:${color};border-radius:${borderRadius};border:3px solid #fff;box-shadow:0 2px 8px rgba(0,0,0,0.25);margin:0 auto;"></div>
    <div class="marker-text">${name}</div>
  </div>`
  const label = new BMapGL.Label(html, {
    position: point,
    offset: new BMapGL.Size(-size / 2 - 3, -size - 8)
  })
  label.setStyle({ border: 'none', background: 'transparent', padding: '0' })
  try {
    label.addEventListener('click', (e) => {
      overlayClicked = true
      e.domEvent && e.domEvent.stopPropagation && e.domEvent.stopPropagation()
      onClick && onClick()
    })
  } catch (_) { /* marker click listener failed */ }
  mapInstance.addOverlay(label)
}

function showPopup(lng, lat, html) {
  try {
    closeInfoWindow()
    const point = new BMapGL.Point(lng, lat)
    const infoWindow = new BMapGL.InfoWindow(html, {
      width: 310,
      title: '',
      enableMessage: false
    })
    activeInfoWindow = infoWindow
    mapInstance.openInfoWindow(infoWindow, point)
  } catch (e) {
    console.warn('弹出信息窗口失败：', e)
  }
}

function closeInfoWindow() {
  if (activeInfoWindow && mapInstance) {
    mapInstance.closeInfoWindow()
    activeInfoWindow = null
  }
}

function buildPopupHTML(detail) {
  const rows = Object.entries(detail.details)
    .map(([k, v]) => `<div class="popup-row"><span class="popup-label">${k}</span><span class="popup-value">${v}</span></div>`)
    .join('')
  return `<div class="info-popup">
    <div class="popup-header">${detail.name}</div>
    <div class="popup-tag">${detail.category}</div>
    <div class="popup-divider"></div>
    ${rows}
  </div>`
}

function buildPipelineDetail(item) {
  return {
    name: item.name,
    category: labelMap[item.level],
    details: {
      '管线编号': item.code,
      '所属道路': item.road,
      '管线长度': `${item.length} km`,
      '管径': item.diameter,
      '材质': item.material,
      '压力等级': item.pressure,
      '敷设方式': item.layingMethod,
      '埋深': item.depth,
      '投产日期': item.commissioningDate,
      '运行状态': item.status
    }
  }
}

function getPipelineName(pipelineId) {
  const found = pipelineData.find(p => p.id === pipelineId)
  return found ? found.name : '—'
}

function buildPipePointDetail(item) {
  return {
    name: item.name,
    category: labelMap[item.type],
    details: {
      '设备编号': item.code,
      '所属管线': getPipelineName(item.pipelineId),
      '所属道路': item.road,
      '设备型号': item.deviceModel,
      '口径': item.caliber,
      '运行状态': item.status,
      '经度': item.lng.toFixed(5),
      '纬度': item.lat.toFixed(5)
    }
  }
}

function buildManholeDetail(item) {
  return {
    name: item.name,
    category: labelMap[item.type],
    details: {
      '井盖编号': item.code,
      '所属管线': getPipelineName(item.pipelineId),
      '所属道路': item.road,
      '材质': item.material,
      '规格': item.size,
      '巡检状态': item.status,
      '经度': item.lng.toFixed(5),
      '纬度': item.lat.toFixed(5)
    }
  }
}

function getMidPoint(points) {
  return points[Math.floor(points.length / 2)]
}

function handleSearch() {
  const keyword = searchKeyword.value.trim()
  if (!keyword) {
    ElMessage.warning('请输入搜索关键字')
    return
  }

  const matched = searchableFeatures.value.find(item =>
    [item.name, item.code, item.road].some(text => text?.includes(keyword))
  )

  if (!matched) {
    ElMessage.info('未找到匹配要素')
    return
  }

  const [mlng, mlat] = convertCoord(matched.lng, matched.lat)
  mapInstance.centerAndZoom(new BMapGL.Point(mlng, mlat), 18)

  if (matched.kind === 'pipeline') {
    selectedFeature.value = buildPipelineDetail(matched.raw)
    showPopup(mlng, mlat, buildPopupHTML(selectedFeature.value))
  } else if (matched.kind === 'pipePoint') {
    selectedFeature.value = buildPipePointDetail(matched.raw)
    showPopup(mlng, mlat, buildPopupHTML(selectedFeature.value))
  } else {
    selectedFeature.value = buildManholeDetail(matched.raw)
    showPopup(mlng, mlat, buildPopupHTML(selectedFeature.value))
  }

  ElMessage.success(`已定位到 ${matched.name}`)
}

async function refreshScene() {
  layerState.pipelines = { high: true, subHigh: true, medium: true, low: true }
  layerState.pipePoints = { valve: true, regulator: true, flowmeter: true, terminal: true }
  layerState.manholes = { cover: true, inspection: true }
  searchKeyword.value = ''
  selectedFeature.value = null
  closeInfoWindow()
  await loadGisData()
  locateCenter()
}

function locateCenter() {
  if (!mapInstance) return
  const [clng, clat] = convertCoord(centerPoint.lng, centerPoint.lat)
  mapInstance.centerAndZoom(new BMapGL.Point(clng, clat), MAP_DEFAULT_ZOOM)
}

function zoomIn() {
  if (!mapInstance) return
  const z = mapInstance.getZoom()
  if (z < MAP_MAX_ZOOM) mapInstance.zoomIn()
  else ElMessage.info('已放大至最大级别')
}

function zoomOut() {
  if (!mapInstance) return
  const z = mapInstance.getZoom()
  if (z > MAP_MIN_ZOOM) mapInstance.zoomOut()
  else ElMessage.info('已缩小至最小级别')
}

function toggleFullscreen() {
  const target = screenRef.value
  if (!target) return
  if (!document.fullscreenElement) {
    target.requestFullscreen?.()
    return
  }
  document.exitFullscreen?.()
}

function handleFullscreenChange() {
  if (!mapInstance) return
  const [clng, clat] = convertCoord(centerPoint.lng, centerPoint.lat)
  setTimeout(() => {
    mapInstance.centerAndZoom(new BMapGL.Point(clng, clat), mapInstance.getZoom())
  }, 200)
}
</script>

<style scoped>
.gis-dashboard {
  height: calc(100vh - 84px);
  padding: 16px;
  background: #f2f5f9;
  display: flex;
  flex-direction: column;
  gap: 0;
}

.dashboard-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 10px 16px;
  margin-bottom: 14px;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 4px 16px rgba(15, 35, 95, 0.05);
  flex-shrink: 0;
}

.header-title {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
}

.title-main {
  display: flex;
  align-items: center;
  gap: 8px;
  color: #1f2d3d;
  font-size: 17px;
  font-weight: 700;
}

.title-metrics {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}

.metric {
  position: relative;
  padding-left: 14px;
  color: #44546a;
  font-size: 13px;
}

.metric::before {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  transform: translateY(-50%);
}

.metric-danger::before { background: #e63946; }
.metric-primary::before { background: #457b9d; }
.metric-warning::before { background: #7f4f24; }

.header-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

.search-input {
  width: 300px;
}

.dashboard-content {
  flex: 1;
  display: flex;
  gap: 14px;
  min-height: 0;
}

.dashboard-sidebar {
  width: 320px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  flex-shrink: 0;
  overflow-y: auto;
}

.panel-card {
  border: none;
  border-radius: 14px;
  box-shadow: 0 4px 18px rgba(15, 35, 95, 0.05);
  flex-shrink: 0;
}

.layer-group {
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding-bottom: 16px;
  margin-bottom: 16px;
  border-bottom: 1px solid #eef2f8;
}

.layer-group-last {
  padding-bottom: 0;
  margin-bottom: 0;
  border-bottom: none;
}

.layer-title {
  color: #303133;
  font-size: 14px;
  font-weight: 600;
}

.legend-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.legend-item {
  display: flex;
  align-items: center;
  gap: 10px;
  color: #4e5969;
  font-size: 13px;
}

.legend-line {
  width: 34px;
  height: 0;
  border-top-width: 3px;
  border-top-style: solid;
  border-radius: 999px;
  flex-shrink: 0;
}

.legend-high { border-top-color: #e63946; }
.legend-sub-high { border-top-color: #f77f00; }
.legend-medium { border-top-color: #fcbf49; }
.legend-low { border-top-color: #2a9d8f; }

.legend-dot,
.legend-square {
  width: 12px;
  height: 12px;
  flex-shrink: 0;
}

.legend-dot { border-radius: 50%; }
.legend-square { border-radius: 2px; }
.legend-valve { background: #457b9d; }
.legend-regulator { background: #e76f51; }
.legend-flowmeter { background: #2d6a4f; }
.legend-terminal { background: #6c757d; }
.legend-cover { background: #7f4f24; }
.legend-inspection { background: #b08968; }

.stats-card {
  background: linear-gradient(180deg, #f8fbff 0%, #f3f7fb 100%);
}

.stats-list {
  display: flex;
  flex-direction: column;
  gap: 11px;
}

.stats-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: #4e5969;
  font-size: 13px;
}

.stats-row strong {
  color: #1f2d3d;
  font-size: 14px;
}

.detail-card {
  flex: 1;
  min-height: 280px;
}

.detail-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.detail-name {
  color: #1f2d3d;
  font-size: 16px;
  font-weight: 700;
}

.detail-tag {
  display: inline-flex;
  align-items: center;
  width: fit-content;
  padding: 3px 10px;
  color: #2d6cdf;
  background: #edf4ff;
  border-radius: 999px;
  font-size: 12px;
}

.dashboard-map-panel {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  background: #fff;
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 4px 18px rgba(15, 35, 95, 0.05);
  min-width: 0;
}

.map-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 16px;
  border-bottom: 1px solid #edf2f7;
  flex-shrink: 0;
}

.toolbar-left {
  display: flex;
  align-items: center;
  gap: 8px;
}

.toolbar-right {
  color: #7a8699;
  font-size: 13px;
}

.gis-map {
  flex: 1;
  min-height: 0;
  background: #e9f0e5;
}

.map-error {
  position: absolute;
  inset: 52px 0 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #909399;
  background: rgba(255, 255, 255, 0.85);
  font-size: 15px;
  z-index: 10;
}
</style>

<style>
.pipe-label {
  padding: 2px 8px;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.3;
  white-space: nowrap;
  text-shadow: 0 0 4px #fff, 0 0 4px #fff;
  background: rgba(255, 255, 255, 0.7);
  border-radius: 10px;
}

.marker-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.marker-text {
  margin-top: 3px;
  padding: 1px 7px;
  color: #2f3a4f;
  font-size: 11px;
  line-height: 1.3;
  white-space: nowrap;
  background: rgba(255, 255, 255, 0.78);
  border-radius: 10px;
  text-shadow: 0 0 3px #fff;
}

.info-popup {
  padding: 4px 2px;
  font-size: 13px;
  color: #333;
}

.popup-header {
  font-size: 15px;
  font-weight: 700;
  color: #1a1a2e;
  margin-bottom: 6px;
}

.popup-tag {
  display: inline-block;
  padding: 2px 10px;
  font-size: 11px;
  color: #1d4ed8;
  background: #eff6ff;
  border-radius: 999px;
  margin-bottom: 10px;
}

.popup-divider {
  height: 1px;
  background: #e5e7eb;
  margin-bottom: 10px;
}

.popup-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 5px 0;
  border-bottom: 1px dashed #f0f0f0;
  font-size: 12px;
  line-height: 1.5;
}

.popup-row:last-child {
  border-bottom: none;
}

.popup-label {
  color: #6b7280;
  flex-shrink: 0;
  margin-right: 12px;
}

.popup-value {
  color: #1f2937;
  font-weight: 500;
  text-align: right;
  word-break: break-all;
}

.BMap_cpyCtrl,
.anchorBL {
  display: none;
}
</style>
