<template>
  <div class="cockpit-layout">
    <!-- <PageHeader /> -->
    <PageHeader />
    <div class="cockpit-main">
      <!-- 地图底层 -->
      <div class="map-layer">
        <MapCenter />
      </div>

      <!-- 地图遮罩层 -->
      <div class="map-mask" aria-hidden="true"></div>

      <!-- 浮动面板层 -->
      <div class="panels-layer">
        <div class="panel-column left-panel">
          <WeatherWarning ref="weatherWarningRef" />
          <EmergencyResources @clickEmergencyResource="handleEmergencyResourceClick" />
        </div>

        <div class="center-spacer" aria-hidden="true"></div>

        <div class="panel-column right-panel">
          <BlockEvent />
          <YearStatistics />
        </div>
      </div>

      <!-- 图例工具栏 -->
      <LegendToolbar class="legend-toolbar" v-model="legendToolActiveItem" :legendKeys="legendKeys"
        @marker-toggle="handleLegendMarkerToggle" />

      <!-- 应急力量详情提示框 -->
      <EmergencyForceTooltip :visible="emergencyForceInteraction.tooltipVisible.value"
        :position="emergencyForceInteraction.tooltipPosition.value" :data="emergencyForceInteraction.tooltipData.value"
        :loading="emergencyForceInteraction.loading.value" :error="emergencyForceInteraction.error.value"
        @close="emergencyForceInteraction.hideTooltip" />
    </div>
  </div>
</template>

<script setup>
import { ref, onBeforeUnmount, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import useMapStore from '@/map/stores/mapStore'
import { fetchEmergencyForceList } from '@/views/cockpit/api/emergencyForce'
import { useEmergencyForceInteraction } from '../composables/useEmergencyForceInteraction'
import { useMapBase } from '../composables/useMapBase'
import { useMapImageMark } from '../composables/useMapImageMark'

import PageHeader from './PageHeader.vue'
import WeatherWarning from './WeatherWarning.vue'
import EmergencyResources from './EmergencyResources.vue'
import MapCenter from './MapCenter.vue'
import BlockEvent from './BlockEvent.vue'
import YearStatistics from './YearStatistics.vue'
import LegendToolbar from './LegendToolbar.vue'
import EmergencyForceTooltip from './EmergencyForceTooltip.vue'
import emergencyForceMarkerIcon from '../assets/legendTool/应急力量icon定位.png'

onMounted(() => {
  // 加载地图业务底图 并 聚焦中心点
  mapBase.loadBaseData()

  weatherWarningRef.value.loadData()
})

// ==================== 常量定义 ====================

/**
 * 应急力量图层 ID
 * 用于在地图上标识和管理应急力量标记点
 */
const EMERGENCY_FORCE_LAYER_ID = 'legend:emergencyForce'

/**
 * 应急力量数据缓存时间（毫秒）
 * 60秒内重复点击使用缓存数据，减少服务器压力
 */
const EMERGENCY_FORCE_CACHE_TTL = 60 * 1000

// ==================== 组件实例 ====================
const weatherWarningRef = ref(null)

// ==================== 状态管理 ====================

const mapStore = useMapStore()

/**
 * 应急力量地图交互
 * 处理点击事件和详情显示
 */
const emergencyForceInteraction = useEmergencyForceInteraction(mapStore, {
  flyToPoint: false, // 默认不飞行，可配置
  flyDuration: 1.5,
  flyDistance: 500
})

/**
 * 加载地图的业务底图与聚焦中心点
 */
const mapBase = useMapBase(mapStore)

/**
 * 标记图hook，搭配lengendToolbar使用, 作用是点击某个图例项时，在地图上显示所有该图例的图
 */
const mapImageMarkHook = useMapImageMark(mapStore)

/**
 * 应急力量数据加载状态
 */
const emergencyForceLoading = ref(false)

/**
 * 应急力量图层激活状态
 */
const emergencyForceActive = ref(false)

/**
 * 应急力量数据缓存
 * @type {Ref<{data: Array|null, expiresAt: number}>}
 */
const emergencyForceCache = ref({
  data: null,
  expiresAt: 0
})

/**
 * 请求取消控制器
 * 用于在组件卸载或用户取消操作时中止正在进行的请求
 */
const emergencyForceAbortController = ref(null)

/**
 * 工具图标列表通过key关联
 * key具体有哪些，请根据LegendToolbar.vue中定义的defaultLegendItems
 * 后续的ImageMarkData中也需要与这里的key值对应
 */
const legendKeys = ref(['serviceFacility', 'riskRoad', 'blockEvent', 'weatherAlert', 'emergencyForce'])

/**
 * 过滤标记对象，存放当前需要过滤的关键字
 */
const filterMark = ref({
  serviceFacility: []
})

/**
 * 图例项
 */
const legendToolActiveItem = ref([])

// ==================== 工具函数 ====================

/**
 * 安全地将值转换为数字
 * @param {*} value - 待转换的值
 * @returns {number|null} 有效数字或 null
 */
const toNumber = (value) => {
  const num = Number(value)
  return Number.isFinite(num) ? num : null
}

/**
 * 坐标系转换（预留接口）
 * 如果后端返回的坐标不是 WGS84，可以在此进行转换
 * 常见坐标系：GCJ-02（火星坐标）、BD-09（百度坐标）
 *
 * @param {number} lon - 经度
 * @param {number} lat - 纬度
 * @returns {{lon: number, lat: number}} 转换后的坐标
 */
const transformToWGS84 = (lon, lat) => {
  // TODO: 如果后端坐标为 GCJ-02 或 BD-09，需要在此进行坐标转换
  // 可以使用 coordtransform 等库进行转换
  return { lon, lat }
}

/**
 * 创建请求取消控制器
 * @returns {AbortController|null}
 */
const createAbortController = () => {
  if (typeof AbortController === 'undefined') {
    console.warn('当前环境不支持 AbortController')
    return null
  }
  return new AbortController()
}

/**
 * 取消正在进行的应急力量数据请求
 */
const cancelEmergencyForceRequest = () => {
  if (emergencyForceAbortController.value) {
    try {
      emergencyForceAbortController.value.abort()
    } catch (error) {
      console.warn('取消请求失败', error)
    } finally {
      emergencyForceAbortController.value = null
    }
  }
}

/**
 * 获取地图实体服务
 * @param {Object} options - 配置选项
 * @param {boolean} [options.silent=false] - 是否静默模式（不显示错误提示）
 * @returns {Object|null} 实体服务对象或 null
 */
const getEntityService = (options = {}) => {
  const silent = options.silent ?? false

  if (!mapStore.isReady()) {
    if (!silent) {
      ElMessage.warning('地图尚未就绪，请稍后再试')
    }
    return null
  }

  try {
    return mapStore.services().entity
  } catch (error) {
    if (!silent) {
      ElMessage.error('地图服务暂不可用')
    }
    console.error('获取地图实体服务失败', error)
    return null
  }
}

/**
 * 清除地图上的应急力量标记点
 */
const clearEmergencyForceMarkers = () => {
  const entityService = getEntityService({ silent: true })
  if (!entityService) return

  try {
    entityService.clearLayerEntities(EMERGENCY_FORCE_LAYER_ID)
  } catch (error) {
    console.error('清除应急力量标记失败', error)
  }
}

// ==================== 数据处理 ====================

/**
 * 解析应急力量列表响应数据
 * 兼容多种响应格式
 *
 * @param {*} response - API 响应数据
 * @returns {Array} 应急力量点位数组
 * @throws {Error} 当响应为空、包含错误码或格式无效时抛出异常
 */
const resolveEmergencyForceList = (response) => {
  // 处理空响应 - 抛出错误而不是静默返回空数组
  if (!response) {
    throw new Error('应急力量数据请求失败，未收到有效响应')
  }

  // 直接返回数组
  if (Array.isArray(response)) {
    return response
  }

  // 处理标准响应格式 { code, data, message }
  if (response.code) {
    // 检查错误码（假设 '00000' 表示成功）
    if (response.code !== '00000') {
      throw new Error(response.message || '应急力量数据获取失败')
    }
  }

  // 提取 data 字段
  if (Array.isArray(response.data)) {
    return response.data
  }

  // 无法识别的格式 - 抛出错误
  console.error('无法识别的应急力量数据格式', response)
  throw new Error('应急力量数据格式错误')
}

/**
 * 标准化应急力量点位数据
 * 提取并验证经纬度，过滤无效数据
 *
 * @param {Array} records - 原始数据记录
 * @returns {Array<{id: string, lon: number, lat: number, meta: Object}>} 标准化后的点位数据
 */
const normalizeEmergencyForcePoints = (records) => {
  if (!Array.isArray(records)) {
    return []
  }

  return records
    .map((item, index) => {
      // 尝试多种可能的字段名提取经度
      const lon = toNumber(
        item?.jd ?? item?.lon ?? item?.lng ?? item?.longitude
      )

      // 尝试多种可能的字段名提取纬度
      const lat = toNumber(
        item?.wd ?? item?.lat ?? item?.latitude
      )

      // 过滤无效坐标
      if (lon === null || lat === null) {
        console.warn('应急力量点位缺少有效坐标', item)
        return null
      }

      // 坐标系转换
      const coords = transformToWGS84(lon, lat)

      return {
        id: item?.id ? `emergencyForce-${item.id}` : `emergencyForce-${index}`,
        lon: coords.lon,
        lat: coords.lat,
        meta: { ...item } // 保留原始数据用于后续使用
      }
    })
    .filter(Boolean) // 过滤掉 null 值
}

/**
 * 加载应急力量点位数据
 * 优先使用缓存，缓存过期则重新请求
 *
 * @returns {Promise<{data: Array, fromCache: boolean}>} 标准化后的点位数据和缓存标识
 * @throws {Error} 请求失败时抛出异常
 */
const loadEmergencyForcePoints = async () => {
  const now = Date.now()

  // 检查缓存是否有效
  if (
    emergencyForceCache.value.data &&
    emergencyForceCache.value.expiresAt > now
  ) {
    console.log('使用缓存的应急力量数据')
    return {
      data: emergencyForceCache.value.data,
      fromCache: true
    }
  }

  // 创建取消控制器
  const controller = createAbortController()
  if (controller) {
    emergencyForceAbortController.value = controller
  }

  try {
    // 发起 API 请求
    const response = await fetchEmergencyForceList(
      controller ? { signal: controller.signal } : {}
    )

    // 解析和标准化数据
    const list = resolveEmergencyForceList(response)
    const points = normalizeEmergencyForcePoints(list)

    // 更新缓存
    emergencyForceCache.value = {
      data: points,
      expiresAt: now + EMERGENCY_FORCE_CACHE_TTL
    }

    return {
      data: points,
      fromCache: false
    }
  } finally {
    // 清理取消控制器
    emergencyForceAbortController.value = null
  }
}

/**
 * 在地图上渲染应急力量点位
 *
 * @param {Object} entityService - 地图实体服务
 * @param {Array} points - 点位数据
 * @param {string} [markerIcon] - 标记图标 URL
 * @returns {Promise<void>}
 */
const renderEmergencyForcePoints = async (entityService, points, markerIcon) => {
  if (!entityService) {
    return
  }

  // 清除旧标记
  entityService.clearLayerEntities(EMERGENCY_FORCE_LAYER_ID)

  if (!points.length) {
    return
  }

  const icon = markerIcon || emergencyForceMarkerIcon

  try {
    // 批量添加标记点
    await Promise.all(
      points.map((point) =>
        entityService.addBillboard({
          id: point.id,
          layerId: EMERGENCY_FORCE_LAYER_ID,
          position: [point.lon, point.lat, 0],
          image: icon,
          width: 44,
          height: 44,
          clampToGround: true,
          properties: point.meta
        })
      )
    )

    console.log(`成功渲染 ${points.length} 个应急力量点位`)
  } catch (error) {
    console.error('渲染应急力量点位失败', error)
    throw error
  }
}

// ==================== 事件处理 ====================

/**
 * 应急资源表格行被点击时触发
 */
const handleEmergencyResourceClick = (resource) => {
  let focusKey = null

  // 根据区县名称，过滤养护站
  const filterList = filterMark.value.serviceFacility
  const index = filterList.findIndex((item) => item == resource.qxmc)
  // 实现第一次点击表示选中，第二次点击表示取消选中
  if (index > -1) {
    filterList.splice(index, 1)
  }
  else {
    filterList.push(resource.qxmc)
    focusKey = resource.qxmc
  }

  // 当点击了某个区县，需要将养护站的legend也点亮
  const legendIndex = legendToolActiveItem.value.indexOf('serviceFacility')
  // 如果过滤列表存在数据，则需要点亮legend
  if (filterList.length && legendIndex == -1) {
    legendToolActiveItem.value.push('serviceFacility')
  }
  // 如果过滤列表不存在，则需要关闭legend
  if (!filterList.length && legendIndex > -1) {
    legendToolActiveItem.value.splice(legendIndex, 1)
  }

  // 调用图例hook来进行数据的请求与图例的绘制，第一个回调函数是过滤点位，第二个是聚焦点位
  mapImageMarkHook.filterYHZMark(
    "serviceFacility",
    (item) => {
      return filterList.find((filterItem) => filterItem == item.qxmc)
    },
    (item) => {
      return item.qxmc == focusKey
    }
  )

}

/**
 * 处理图例工具栏的标记切换事件
 *
 * @param {Object} payload - 事件载荷
 * @param {string} payload.key - 图例项 key
 * @param {boolean} payload.active - 是否激活
 * @param {string} [payload.markerIcon] - 标记图标
 */
const handleLegendMarkerToggle = async ({ key, active, markerIcon }) => {
  if (key === 'riskRoad') {
    mapBase.toggleHighAltitudeRoadMap(active)
    return
  }


  // 只处理应急力量图例项
  if (key !== 'emergencyForce') {
    if (active == false) {
      filterMark.value[key] = []
    }

    mapImageMarkHook.toggleMark({ key, active, markerIcon })

    return
  }

  emergencyForceActive.value = active

  // 关闭图层
  if (!active) {
    cancelEmergencyForceRequest()
    emergencyForceLoading.value = false
    clearEmergencyForceMarkers()

    // 禁用点击交互
    emergencyForceInteraction.enabled.value = false
    return
  }

  // 防止重复加载
  if (emergencyForceLoading.value) {
    console.warn('应急力量数据正在加载中，请勿重复操作')
    return
  }

  // 获取地图服务
  const entityService = getEntityService()
  if (!entityService) {
    emergencyForceActive.value = false
    return
  }

  emergencyForceLoading.value = true

  try {
    // 加载数据
    const result = await loadEmergencyForcePoints()
    const { data: points, fromCache } = result

    // 检查用户是否在加载过程中关闭了图层
    if (!emergencyForceActive.value) {
      console.log('用户已取消应急力量图层显示')
      return
    }

    // 渲染点位
    await renderEmergencyForcePoints(entityService, points, markerIcon)

    // 启用点击交互
    emergencyForceInteraction.enabled.value = true

    // 提示用户（仅在首次加载且有数据时显示成功提示）
    if (!points.length) {
      ElMessage.warning('未获取到应急力量点位数据')
    } else if (!fromCache) {
      // 只在非缓存数据时显示成功提示
      ElMessage.success(`已加载 ${points.length} 个应急力量点位`)
    }
  } catch (error) {
    // 处理请求取消
    if (error.name === 'AbortError' || error.name === 'CanceledError') {
      console.log('应急力量数据请求已取消')
      return
    }

    // 处理其他错误
    console.error('加载应急力量点位失败', error)
    ElMessage.error(error?.message || '应急力量数据加载失败，请稍后重试')
    clearEmergencyForceMarkers()

    // 重置图层激活状态，避免 UI 不一致
    emergencyForceActive.value = false
  } finally {
    emergencyForceLoading.value = false
    cancelEmergencyForceRequest()
  }
}

// ==================== 生命周期 ====================

/**
 * 组件卸载前清理资源
 */
onBeforeUnmount(() => {
  emergencyForceActive.value = false
  cancelEmergencyForceRequest()
  clearEmergencyForceMarkers()
})
</script>

<style scoped lang="scss">
/**
 * 驾驶舱布局 - 可嵌入组件
 *
 * 此组件设计为可嵌入到其他系统中（iframe/组件）。
 * 使用百分比和 rem 单位而非 vw/vh，以适应父容器尺寸。
 *
 * CSS 自定义属性（可被父级覆盖）：
 * - --cockpit-side-width: 侧边栏宽度（默认：minmax(15rem, 28%)）
 * - --cockpit-gap: 网格间距和面板间距（默认：1.25rem）
 * - --cockpit-padding-x: 水平内边距（默认：0.625rem）
 * - --cockpit-padding-top: 顶部内边距（默认：0）
 * - --cockpit-padding-bottom: 底部内边距（默认：0）
 * - --cockpit-min-height: 最小高度（默认：600px）
 *
 * 父级使用方式：<CockpitLayout style="--cockpit-gap: 2rem" />
 * 窄容器嵌入（<1100px 宽度）时，添加 .is-compact 修饰符类：
 *   <CockpitLayout class="is-compact" />
 * 如需在滚动父容器中嵌入，可覆盖 overflow: hidden
 *
 * 浏览器兼容性：需要 CSS 自定义属性支持（Chrome 49+, Safari 9.1+, Firefox 31+）
 * 未来计划：支持容器查询以实现响应式窄屏布局
 *
 * 基于 1920px 设计稿，根字体大小 16px
 */
.cockpit-layout {
  /* 容器查询设置，用于嵌入场景的自适应缩放 */
  container-name: cockpit-layout;
  container-type: size;

  /* 为旧版浏览器提供视口单位回退 */
  --cq-inline-100: 100vw;
  --cq-block-100: 100vh;

  /* 当支持容器单位时覆盖为容器单位 */
  @supports (width: 1cqw) {
    --cq-inline-100: 100cqw;
  }

  @supports (height: 1cqh) {
    --cq-block-100: 100cqh;
  }

  /* 嵌入场景的 CSS 自定义属性 */
  --cockpit-side-width: minmax(15rem, 28%);
  --cockpit-gap: 1rem;
  --cockpit-padding-x: 0.625rem;
  --cockpit-padding-top: 0;
  --cockpit-padding-bottom: 0;
  --cockpit-min-height: 600px;

  /* 使用 100% 填充父容器而非视口 */
  width: 100%;
  height: 100%;
  min-height: var(--cockpit-min-height);
  min-width: 0;
  /* 允许 flex 子元素收缩 */

  background: url(../assets/img/cockpit-main-bg.png) no-repeat;
  background-size: cover;
  display: flex;
  flex-direction: column;
  overflow: auto;
  /* 当宿主高度 < 最小高度时允许滚动 */
}

/* 窄容器嵌入的紧凑布局（<1100px 宽度）*/
.cockpit-layout.is-compact {
  --cockpit-side-width: minmax(12rem, 24%);
  --cockpit-gap: 1rem;
}

.cockpit-main {
  position: relative;
  flex: 1;
  min-height: 0;
  /* 允许网格在 flex 上下文中收缩 */
  overflow: hidden;
  /* 防止内容溢出 */
}

/* 地图底层 - 填满整个容器 */
.map-layer {
  position: absolute;
  inset: 0;
  z-index: 0;
  /* 不设置 pointer-events，让地图保持可交互 */
}

/* 地图遮罩层 - 覆盖在地图之上 */
.map-mask {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  /* 不阻挡交互 */
  background: url(../assets/img/遮罩层.png) no-repeat center/cover;
}

/* 浮动面板层 - grid 与 pointer-events 结合保证中间透明 */
.panels-layer {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: var(--cockpit-side-width) 1fr var(--cockpit-side-width);
  grid-auto-rows: 1fr;
  gap: var(--cockpit-gap);
  height: 100%;
  box-sizing: border-box;
  pointer-events: none;
  /* 容器不拦截事件，让中间区域透明 */
}

/* 中间占位区域 - 透明且不可交互，点击穿透到地图 */
.center-spacer {
  pointer-events: none;
}

/* 左右面板列 - 浮动卡片样式 */
.panel-column {
  display: flex;
  flex-direction: column;
  gap: var(--cockpit-gap);
  min-width: 0;
  /* 防止在窄容器中溢出 */
  min-height: 0;
  /* 允许 flex 子元素收缩并启用滚动 */
  padding: 1rem;
  pointer-events: auto;
  /* 恢复面板的交互能力 */
}

/* 图例工具栏 - 居中显示在底部 */
.legend-toolbar {
  position: absolute;
  bottom: var(--cockpit-gap);
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  pointer-events: auto;
  /* 确保图例可交互 */
}
</style>
