<template>
  <div v-loading="loading">
    <PageHeader title="无人机运行" description="管理厂商连接、设备能力、飞行任务、命令回执和遥测航迹">
      <el-button :icon="Refresh" @click="load">刷新</el-button>
      <el-button type="primary" :icon="Promotion" @click="openDispatchDialog()">下发任务</el-button>
    </PageHeader>

    <section class="metric-strip">
      <div class="metric-card"><strong>{{ connections.length }}</strong><span>厂商连接</span><small>{{ availableConnections }} 个业务握手可用</small></div>
      <div class="metric-card"><strong>{{ devices.length }}</strong><span>无人机设备</span><small>{{ onlineDevices }} 架在线</small></div>
      <div class="metric-card"><strong>{{ activeMissions }}</strong><span>执行中任务</span><small>下发、飞行与返航</small></div>
      <div class="metric-card"><strong>{{ completedMissions }}</strong><span>已完成任务</span><small>统一任务状态记录</small></div>
    </section>

    <el-tabs v-model="activeTab" class="secondary-tabs">
      <el-tab-pane label="厂商连接" name="connections">
        <el-card class="workspace-card" shadow="never"><el-table :data="connections" empty-text="暂无厂商连接">
          <el-table-column prop="name" label="连接" min-width="180"><template #default="scope"><strong>{{ scope.row.name }}</strong><small class="cell-subtext">{{ scope.row.connection_mode }} / {{ scope.row.environment }}</small></template></el-table-column>
          <el-table-column prop="vendor_code" label="厂商" width="105" />
          <el-table-column label="能力" min-width="200"><template #default="scope"><span class="capability-list">{{ parseArray(scope.row.capabilities).join(' / ') || '等待授权后同步' }}</span></template></el-table-column>
          <el-table-column label="设备" width="80"><template #default="scope">{{ scope.row.device_count }}</template></el-table-column>
          <el-table-column label="状态" width="135"><template #default="scope"><el-tag :type="connectionTag(scope.row.status)" effect="plain">{{ connectionLabel(scope.row.status) }}</el-tag></template></el-table-column>
          <el-table-column label="最近检查" min-width="165"><template #default="scope">{{ formatDate(scope.row.last_checked_at) }}</template></el-table-column>
          <el-table-column label="操作" width="205" fixed="right"><template #default="scope"><div class="list-actions"><el-button link type="primary" @click="checkConnection(scope.row)">检查连接</el-button><el-button link type="primary" :disabled="scope.row.status !== 'AVAILABLE'" @click="syncDevices(scope.row)">同步设备</el-button></div></template></el-table-column>
        </el-table></el-card>
      </el-tab-pane>

      <el-tab-pane label="设备台账" name="devices">
        <div class="device-grid"><article v-for="device in devices" :key="device.device_id" class="device-card"><header><div class="device-icon"><el-icon><Position /></el-icon></div><div><strong>{{ device.model }}</strong><span>{{ device.vendor_device_id }}</span></div><el-tag :type="device.status === 'ONLINE' ? 'success' : 'info'" size="small">{{ device.status === 'ONLINE' ? '在线' : device.status }}</el-tag></header><dl><div><dt>厂商</dt><dd>{{ device.vendor_code }}</dd></div><div><dt>连接</dt><dd>{{ device.connection_name }}</dd></div><div><dt>电量</dt><dd>{{ health(device).battery_percent ?? '-' }}%</dd></div><div><dt>链路</dt><dd>{{ health(device).link_quality ?? '-' }}%</dd></div><div><dt>RTK</dt><dd>{{ health(device).rtk || '-' }}</dd></div><div><dt>最近心跳</dt><dd>{{ timeOnly(device.last_seen_at) }}</dd></div></dl><footer>{{ parseArray(device.capabilities).join(' · ') }}</footer></article></div>
      </el-tab-pane>

      <el-tab-pane label="飞行任务" name="missions">
        <el-card class="workspace-card" shadow="never"><el-table :data="missions" empty-text="暂无飞行任务" @row-click="inspectMission">
          <el-table-column prop="mission_id" label="飞行任务" min-width="175"><template #default="scope"><span class="entity-id">{{ scope.row.mission_id }}</span><small class="cell-subtext">{{ scope.row.vendor_mission_id || '等待厂商回执' }}</small></template></el-table-column>
          <el-table-column prop="task_id" label="巡检任务" min-width="165" />
          <el-table-column prop="route_name" label="航线" min-width="130" />
          <el-table-column prop="device_model" label="无人机" min-width="130" />
          <el-table-column prop="vendor_code" label="厂商" width="95" />
          <el-table-column label="进度" min-width="140"><template #default="scope"><el-progress :percentage="scope.row.progress" :stroke-width="8" /></template></el-table-column>
          <el-table-column label="状态" width="105"><template #default="scope"><el-tag :type="missionTag(scope.row.status)" effect="plain">{{ missionLabel(scope.row.status) }}</el-tag></template></el-table-column>
          <el-table-column label="操作" width="330" fixed="right"><template #default="scope"><div class="list-actions" @click.stop><el-button v-if="scope.row.status === 'DISPATCHED' && scope.row.vendor_code === 'SIMULATOR'" link type="primary" @click="command(scope.row, 'MISSION_START')">开始</el-button><el-button v-if="scope.row.status === 'FLYING'" link type="warning" @click="command(scope.row, 'MISSION_PAUSE')">暂停</el-button><el-button v-if="scope.row.status === 'PAUSED'" link type="primary" @click="command(scope.row, 'MISSION_RESUME')">恢复</el-button><el-button v-if="scope.row.status === 'FLYING' && scope.row.vendor_code === 'SIMULATOR'" link type="primary" @click="command(scope.row, 'SIMULATE_PROGRESS')">推进</el-button><el-button v-if="['FLYING','PAUSED'].includes(scope.row.status)" link type="danger" @click="command(scope.row, 'RETURN_HOME')">返航</el-button><el-button v-if="['DISPATCHED','PREPARING'].includes(scope.row.status)" link type="danger" @click="command(scope.row, 'MISSION_CANCEL')">取消</el-button><el-button link @click="inspectMission(scope.row)">遥测</el-button></div></template></el-table-column>
        </el-table></el-card>
      </el-tab-pane>
    </el-tabs>

    <el-dialog v-model="dispatchDialog" title="下发飞行任务" width="min(660px, 94vw)">
      <el-alert type="info" :closable="false" show-icon title="本地环境通过厂商适配器模拟器执行，生产厂商连接缺少授权时禁止下发。" />
      <el-form label-position="top" class="dialog-form"><div class="form-grid"><el-form-item label="待下发巡检任务"><el-select v-model="dispatchForm.task_id" filterable @change="selectTask"><el-option v-for="item in dispatchableTasks" :key="item.task_id" :label="`${item.task_id} / ${item.line_id}`" :value="item.task_id" /></el-select></el-form-item><el-form-item label="已审批航线"><el-input :model-value="selectedTask?.route_name || selectedTask?.route_id || '未配置'" disabled /></el-form-item><el-form-item label="厂商连接"><el-select v-model="dispatchForm.connection_id" @change="selectConnection"><el-option v-for="item in usableConnections" :key="item.connection_id" :label="item.name" :value="item.connection_id" /></el-select></el-form-item><el-form-item label="无人机"><el-select v-model="dispatchForm.device_id"><el-option v-for="item in availableDevices" :key="item.device_id" :label="`${item.model} / ${item.vendor_device_id}`" :value="item.device_id" /></el-select></el-form-item></div></el-form>
      <template #footer><el-button @click="dispatchDialog = false">取消</el-button><el-button type="primary" :loading="saving" @click="dispatch">下发</el-button></template>
    </el-dialog>

    <el-drawer v-model="healthVisible" title="连接检查结果" size="520px"><template v-if="healthResult"><el-result :icon="healthResult.status === 'AVAILABLE' ? 'success' : 'warning'" :title="connectionLabel(healthResult.status)" :sub-title="healthResult.blocker_reason || '四层连接检查已完成'" /><div class="health-check-list"><div v-for="layer in healthResult.layers || []" :key="layer.layer"><el-icon :class="layer.status === 'PASSED' ? 'passed' : 'blocked'"><CircleCheck v-if="layer.status === 'PASSED'" /><Warning v-else /></el-icon><span><strong>{{ layerLabel(layer.layer) }}</strong><small>{{ layer.message }}</small></span><el-tag :type="layer.status === 'PASSED' ? 'success' : 'warning'" size="small">{{ layer.status }}</el-tag></div></div></template></el-drawer>

    <el-drawer v-model="missionVisible" title="飞行任务与遥测" size="620px"><template v-if="selectedMission"><el-descriptions :column="1" border><el-descriptions-item label="任务编号"><span class="entity-id">{{ selectedMission.mission_id }}</span></el-descriptions-item><el-descriptions-item label="厂商回执">{{ selectedMission.vendor_mission_id || '-' }}</el-descriptions-item><el-descriptions-item label="航线">{{ selectedMission.route_name }}</el-descriptions-item><el-descriptions-item label="状态">{{ missionLabel(selectedMission.status) }} / {{ selectedMission.progress }}%</el-descriptions-item></el-descriptions><h3 class="drawer-section-title">遥测时间轴</h3><el-timeline><el-timeline-item v-for="point in telemetry" :key="point.id" :timestamp="formatDate(point.event_time)" placement="top"><strong>{{ Number(point.longitude).toFixed(6) }}, {{ Number(point.latitude).toFixed(6) }}</strong><p>{{ telemetrySummary(point.metrics) }}</p></el-timeline-item></el-timeline><el-empty v-if="telemetry.length === 0" description="任务开始飞行后产生遥测" /></template></el-drawer>
  </div>
</template>

<script setup lang="ts">
import { computed, onMounted, reactive, ref } from "vue";
import { useRoute } from "vue-router";
import { ElMessage } from "element-plus";
import { CircleCheck, Position, Promotion, Refresh, Warning } from "@element-plus/icons-vue";
import PageHeader from "../../components/common/PageHeader.vue";
import { checkUavConnection, dispatchUavMission, executeUavMissionCommand, synchronizeUavDevices, tasks, uavConnections, uavDevices, uavMissions, uavMissionTelemetry } from "../../services/api";
import { safeObject, type Row } from "../../types/demo-run";

const route = useRoute();
const connections = ref<Row[]>([]); const devices = ref<Row[]>([]); const missions = ref<Row[]>([]); const taskRows = ref<Row[]>([]); const loading = ref(false); const saving = ref(false); const activeTab = ref(String(route.query.tab || "connections")); const dispatchDialog = ref(false); const healthVisible = ref(false); const healthResult = ref<Row | null>(null); const missionVisible = ref(false); const selectedMission = ref<Row | null>(null); const telemetry = ref<Row[]>([]); const deepLinkHandled = ref(false);
const dispatchForm = reactive({ task_id: "", route_id: "", connection_id: "connection-simulator", device_id: "uav-sim-01", dock_id: "dock-sim-01" });
const availableConnections = computed(() => connections.value.filter((item) => item.status === "AVAILABLE").length); const onlineDevices = computed(() => devices.value.filter((item) => item.status === "ONLINE").length); const activeMissions = computed(() => missions.value.filter((item) => ["DISPATCHING","DISPATCHED","PREPARING","FLYING","PAUSED","RETURNING"].includes(item.status)).length); const completedMissions = computed(() => missions.value.filter((item) => item.status === "COMPLETED").length); const dispatchableTasks = computed(() => taskRows.value.filter((item) => item.can_dispatch === true || String(item.can_dispatch).toLowerCase() === "true")); const selectedTask = computed(() => taskRows.value.find((item) => String(item.task_id) === dispatchForm.task_id)); const usableConnections = computed(() => connections.value.filter((item) => item.status === "AVAILABLE")); const availableDevices = computed(() => devices.value.filter((item) => item.connection_id === dispatchForm.connection_id && item.status === "ONLINE"));
function parseArray(value: unknown): string[] { try { return Array.isArray(value) ? value.map(String) : JSON.parse(String(value || "[]")); } catch { return []; } }
function health(row: Row) { return safeObject(row.health_detail); }
function connectionLabel(value: unknown) { return ({ AVAILABLE: "服务可用", CONFIGURATION_REQUIRED: "等待部署参数", MATERIALS_REQUIRED: "等待接入材料", DEGRADED: "连接降级", OFFLINE: "不可用" } as Record<string, string>)[String(value)] || String(value); }
function connectionTag(value: unknown): "success" | "warning" | "danger" | "info" { return value === "AVAILABLE" ? "success" : ["CONFIGURATION_REQUIRED","MATERIALS_REQUIRED"].includes(String(value)) ? "warning" : "danger"; }
function missionLabel(value: unknown) { return ({ DISPATCHING: "下发中", DISPATCHED: "已下发", PREPARING: "准备中", FLYING: "飞行中", PAUSED: "已暂停", RETURNING: "返航中", UPLOADING: "数据回传", COMPLETED: "已完成", CANCELLED: "已取消", FAILED: "失败" } as Record<string, string>)[String(value)] || String(value); }
function missionTag(value: unknown): "success" | "warning" | "danger" | "info" | "primary" { if (value === "COMPLETED") return "success"; if (["FAILED","CANCELLED"].includes(String(value))) return "danger"; if (["FLYING","RETURNING"].includes(String(value))) return "primary"; if (value === "PAUSED") return "warning"; return "info"; }
function formatDate(value: unknown) { return value ? new Date(String(value)).toLocaleString("zh-CN", { hour12: false }) : "-"; } function timeOnly(value: unknown) { return value ? new Date(String(value)).toLocaleTimeString("zh-CN", { hour12: false }) : "-"; }
function layerLabel(value: unknown) { return ({ NETWORK: "网络可达", AUTHENTICATION: "身份认证", CAPABILITIES: "能力读取", BUSINESS_HANDSHAKE: "业务握手" } as Record<string, string>)[String(value)] || String(value); }
function telemetrySummary(value: unknown) { const data = safeObject(value); return `电量 ${data.battery_percent ?? '-'}% · 链路 ${data.link_quality ?? '-'}% · RTK ${data.rtk_status || '-'}`; }
async function load() { loading.value = true; try { [connections.value, devices.value, missions.value, taskRows.value] = await Promise.all([uavConnections(), uavDevices(), uavMissions(), tasks()]); if (!dispatchForm.task_id && dispatchableTasks.value.length) dispatchForm.task_id = String(dispatchableTasks.value[0].task_id); selectTask(); if (!usableConnections.value.some((item) => item.connection_id === dispatchForm.connection_id)) dispatchForm.connection_id = String(usableConnections.value[0]?.connection_id || ""); selectConnection(); } finally { loading.value = false; } }
function selectTask() { dispatchForm.route_id = String(selectedTask.value?.route_id || ""); }
function selectConnection() { const first = devices.value.find((item) => item.connection_id === dispatchForm.connection_id && item.status === "ONLINE"); dispatchForm.device_id = first ? String(first.device_id) : ""; dispatchForm.dock_id = ""; }
function openDispatchDialog(taskId?: string) { const target = taskId ? dispatchableTasks.value.find((item) => String(item.task_id) === taskId) : dispatchableTasks.value[0]; if (!target) return ElMessage.warning(taskId ? "该任务当前不可下发，请返回巡检任务查看准备状态" : "当前没有满足审批、航线和状态条件的待下发任务"); dispatchForm.task_id = String(target.task_id); selectTask(); activeTab.value = "missions"; dispatchDialog.value = true; }
async function checkConnection(row: Row) { healthResult.value = await checkUavConnection(String(row.connection_id)); healthVisible.value = true; await load(); }
async function syncDevices(row: Row) { const result = await synchronizeUavDevices(String(row.connection_id)); ElMessage.success(`已同步 ${result.synchronized} 台设备`); await load(); activeTab.value = "devices"; }
async function dispatch() { if (!dispatchForm.task_id || !dispatchForm.route_id || !dispatchForm.device_id) return ElMessage.warning("请选择任务、航线和无人机"); saving.value = true; try { const result = await dispatchUavMission({ ...dispatchForm, requested_by: "user-dispatcher", idempotency_key: `dispatch-${dispatchForm.task_id}-${Date.now()}` }); ElMessage.success(`任务已下发：${result.vendor_mission_id}`); dispatchDialog.value = false; activeTab.value = "missions"; await load(); } finally { saving.value = false; } }
async function command(row: Row, action: string) { const result = await executeUavMissionCommand(String(row.mission_id), action, Number(row.version_no)); ElMessage.success(result.accepted ? `命令已受理，等待司空 2 状态回传：${missionLabel(result.status)}` : `命令完成，任务状态：${missionLabel(result.status)}`); await load(); }
async function inspectMission(row: Row) { selectedMission.value = row; telemetry.value = await uavMissionTelemetry(String(row.mission_id)); missionVisible.value = true; }
onMounted(async () => {
  await load();
  if (deepLinkHandled.value) return;
  deepLinkHandled.value = true;
  if (route.query.dispatchTaskId) openDispatchDialog(String(route.query.dispatchTaskId));
  else if (route.query.missionId) {
    activeTab.value = "missions";
    const mission = missions.value.find((item) => String(item.mission_id) === String(route.query.missionId));
    if (mission) await inspectMission(mission);
  }
});
</script>
