<template>
  <div class="container">
    <div class="page-toolbar">
      <div class="toolbar-left">
        <span class="toolbar-label">当前服务器</span>
        <a-select
          v-model="selectedServerIdentity"
          class="server-select"
          placeholder="输入名称或地址搜索"
          allow-search
          allow-clear
          :loading="serverListLoading"
          :filter-option="filterServerOption"
        >
          <a-option
            v-for="item in serverOptions"
            :key="item.server_identity"
            :value="item.server_identity"
            :label="`${item.name} ${item.host} ${item.ip}`"
          >
            <div class="server-option">
              <span class="server-option-name">{{ item.name }}</span>
              <span class="server-option-ip">{{ item.ip }}</span>
            </div>
          </a-option>
        </a-select>
      </div>
      <div v-if="activeServer" class="toolbar-meta text-muted">{{ activeServer.os }} · {{ activeServer.location }}</div>
    </div>

    <!-- 资源统计：卡片仅展示名称 + 剩余 -->
    <a-spin :loading="statsLoading" style="width: 100%">
      <a-row :gutter="16" class="stats-row">
        <a-col v-for="(panel, idx) in resourcePanels" :key="`card-${panel.key}`" :xs="24" :sm="12" :lg="6">
          <a-card class="stats-card" :bordered="false">
            <div class="stats-content">
              <div class="stats-icon" :class="statsIconClass(idx)">
                <component :is="statsIcons[idx]" />
              </div>
              <div class="stats-info">
                <div class="stats-title">{{ panel.title }}</div>
                <div class="stats-value">{{ panel.remaining }}</div>
              </div>
            </div>
          </a-card>
        </a-col>
      </a-row>

      <!-- 与卡片一一对应的饼图：总值 / 已用 / 剩余 -->
      <a-row :gutter="16" class="pie-row">
        <a-col v-for="panel in resourcePanels" :key="panel.key" :xs="24" :sm="12" :lg="6">
          <a-card class="pie-card" :bordered="false">
            <template #title>
              <span>{{ panel.title }}</span>
            </template>
            <div class="pie-body">
              <div class="pie-chart-slot" :class="{ 'pie-chart-slot--empty': !panel.hasData }">
                <Chart v-if="panel.hasData" :options="panel.pieOptions" height="220px" />
                <a-empty v-else class="pie-empty-inner" :description="emptyPieDescription(panel)" />
              </div>
              <div class="pie-meta text-muted">
                <template v-if="panel.hasData">
                  总值 {{ panel.totalLabel }} · 已用 {{ panel.usedLabel }} · 剩余
                  {{ panel.freeLabel }}
                </template>
                <span v-else class="pie-meta-placeholder" aria-hidden="true">&nbsp;</span>
              </div>
            </div>
          </a-card>
        </a-col>
      </a-row>

      <!-- 磁盘挂载明细（disk_root + data_disks，与 dc-control summary 一致） -->
      <a-row v-if="diskTableRows.length" :gutter="16" class="disk-table-row">
        <a-col :span="24">
          <a-card title="磁盘挂载详情" :bordered="false">
            <a-table :columns="diskTableColumns" :data="diskTableRows" :pagination="false" size="small" :bordered="{ cell: true }" />
          </a-card>
        </a-col>
      </a-row>
    </a-spin>

    <a-row :gutter="16" class="chart-row">
      <a-col :xs="24" :lg="14">
        <a-card title="网络流量（近 6 小时）" :bordered="false">
          <template #extra>
            <a-space>
              <span class="legend-item">
                <span class="legend-dot legend-dot-1"></span>
                <span>接收</span>
              </span>
              <span class="legend-item">
                <span class="legend-dot legend-dot-2"></span>
                <span>发送</span>
              </span>
            </a-space>
          </template>
          <a-spin :loading="chartLoading" class="chart-spin">
            <p v-if="trafficHint" class="traffic-hint text-muted">{{ trafficHint }}</p>
            <div class="chart-container">
              <Chart :options="trafficChartOptions" height="300px" />
            </div>
          </a-spin>
        </a-card>
      </a-col>
      <a-col :xs="24" :lg="10">
        <a-card title="最近告警" :bordered="false">
          <template #extra>
            <span class="text-muted">当前主机 · 共 {{ recentAlerts.length }} 条（最多 5 条）</span>
          </template>
          <a-spin :loading="alertsLoading" class="alert-spin">
            <div v-if="recentAlerts.length" class="alert-list">
              <div v-for="item in recentAlerts" :key="item.id" class="alert-item">
                <div class="alert-item-top">
                  <span class="alert-item-name" :title="item.alert_name">{{ item.alert_name || '-' }}</span>
                  <a-tag v-if="item.severity" size="small" :color="item.severity.color || undefined">
                    {{ item.severity.name }}
                  </a-tag>
                </div>
                <div class="alert-item-meta">
                  <a-tag size="small" :color="alertStatusColor(item.status)">
                    {{ alertStatusText(item.status) }}
                  </a-tag>
                  <span class="alert-item-time">{{ formatAlertTime(item.starts_at) }}</span>
                </div>
                <div v-if="item.summary" class="alert-item-summary text-muted">
                  {{ item.summary }}
                </div>
              </div>
            </div>
            <div v-else class="alert-empty-wrap">
              <a-empty description="暂无与该主机相关的告警" />
            </div>
          </a-spin>
        </a-card>
      </a-col>
    </a-row>
  </div>
</template>

<script lang="ts" setup>
import { computed, onMounted, ref, watch } from 'vue'
import dayjs from 'dayjs'
import { Message } from '@arco-design/web-vue'
import { IconStorage, IconDriveFile, IconCodeSquare, IconFolder } from '@arco-design/web-vue/es/icon'
import Chart from '@/components/chart/index.vue'
import {
  fetchServerList,
  fetchServerMetricsSummary,
  fetchServerNetworkTraffic,
  type HostMetricsSummary,
  type HostNetworkTrafficPayload,
  type ServerItem,
} from '@/api/ops/server'
import { fetchAlertRecords } from '@/api/ops/alertRecord'

interface ServerOption {
  server_identity: string
  name: string
  host: string
  ip: string
  os: string
  location: string
}

/** 单块资源：顶部卡片 + 饼图共用 */
interface OsResourcePanel {
  key: string
  title: string
  remaining: string
  hasData: boolean
  totalLabel: string
  usedLabel: string
  freeLabel: string
  pieOptions: Record<string, unknown>
}

const statsIcons = [IconStorage, IconDriveFile, IconCodeSquare, IconFolder]

function statsIconClass(idx: number) {
  const map = ['stats-icon-primary', 'stats-icon-cyan', 'stats-icon-green', 'stats-icon-purple']
  return map[idx] ?? 'stats-icon-primary'
}

const serverListLoading = ref(false)
const statsLoading = ref(false)
const chartLoading = ref(false)
const alertsLoading = ref(false)

/** 与当前选中主机相关的最近告警（来自 Alert record/list） */
const recentAlerts = ref<any[]>([])

const serverOptions = ref<ServerOption[]>([])
const selectedServerIdentity = ref<string | undefined>(undefined)

const summaryPayload = ref<HostMetricsSummary | null>(null)
const trafficPayload = ref<HostNetworkTrafficPayload | null>(null)

const activeServer = computed(() => serverOptions.value.find((s) => s.server_identity === selectedServerIdentity.value))

const emptyPieOptions = (): Record<string, unknown> => ({
  graphic: [
    {
      type: 'text',
      left: 'center',
      top: 'middle',
      style: {
        text: '暂无数据',
        fill: 'var(--color-text-3)',
        fontSize: 14,
      },
    },
  ],
  series: [],
})

/** 字节类资源饼图（已用 / 剩余） */
function buildPieOptionsBytes(usedBytes: number, freeBytes: number, usedColor: string): Record<string, unknown> {
  const u = Math.max(0, usedBytes)
  const f = Math.max(0, freeBytes)
  if (u + f <= 0) return emptyPieOptions()
  return {
    tooltip: {
      trigger: 'item',
      formatter: (p: { name?: string; value?: number; percent?: number }) => {
        const v = p.value ?? 0
        return `${p.name}<br/>${formatBytes(v)} (${p.percent ?? 0}%)`
      },
    },
    legend: { bottom: 0, itemWidth: 10, itemHeight: 10, textStyle: { fontSize: 12 } },
    series: [
      {
        type: 'pie',
        radius: ['42%', '68%'],
        avoidLabelOverlap: false,
        label: { show: false },
        data: [
          { name: '已用', value: u, itemStyle: { color: usedColor } },
          { name: '剩余', value: f, itemStyle: { color: '#E5E6EB' } },
        ],
      },
    ],
  }
}

/** CPU 核数饼图（已用 / 剩余） */
function buildPieOptionsCores(usedCores: number, freeCores: number, usedColor: string): Record<string, unknown> {
  const u = Math.max(0, usedCores)
  const f = Math.max(0, freeCores)
  if (u + f <= 0) return emptyPieOptions()
  return {
    tooltip: {
      trigger: 'item',
      formatter: (p: { name?: string; value?: number; percent?: number }) => {
        const v = p.value ?? 0
        return `${p.name}<br/>${round1(v)} 核 (${p.percent ?? 0}%)`
      },
    },
    legend: { bottom: 0, itemWidth: 10, itemHeight: 10, textStyle: { fontSize: 12 } },
    series: [
      {
        type: 'pie',
        radius: ['42%', '68%'],
        avoidLabelOverlap: false,
        label: { show: false },
        data: [
          { name: '已用', value: u, itemStyle: { color: usedColor } },
          { name: '剩余', value: f, itemStyle: { color: '#E5E6EB' } },
        ],
      },
    ],
  }
}

const defaultResourcePanels: OsResourcePanel[] = [
  {
    key: 'memory',
    title: '内存',
    remaining: '-',
    hasData: false,
    totalLabel: '-',
    usedLabel: '-',
    freeLabel: '-',
    pieOptions: emptyPieOptions(),
  },
  {
    key: 'systemDisk',
    title: '磁盘（系统盘 /）',
    remaining: '-',
    hasData: false,
    totalLabel: '-',
    usedLabel: '-',
    freeLabel: '-',
    pieOptions: emptyPieOptions(),
  },
  {
    key: 'cpu',
    title: 'CPU',
    remaining: '-',
    hasData: false,
    totalLabel: '-',
    usedLabel: '-',
    freeLabel: '-',
    pieOptions: emptyPieOptions(),
  },
  {
    key: 'dataDisk',
    title: '本地挂载（汇总）',
    remaining: '-',
    hasData: false,
    totalLabel: '-',
    usedLabel: '-',
    freeLabel: '-',
    pieOptions: emptyPieOptions(),
  },
]

function round1(n: number) {
  return Math.round(n * 10) / 10
}

function formatPercent(n: number | undefined | null): string {
  if (n === undefined || n === null || Number.isNaN(n)) return '-'
  return `${round1(n)}%`
}

/** 饼图无数据时的说明（区分「无根分区」与「无其它挂载点」） */
function emptyPieDescription(panel: OsResourcePanel): string {
  const sum = summaryPayload.value
  if (!sum?.has_data) return '暂无数据'
  if (panel.key === 'systemDisk' && !panel.hasData) {
    return '暂无根分区磁盘指标（请确认 dc-host 与入库）'
  }
  if (panel.key === 'dataDisk' && !panel.hasData) {
    return '暂无其它本地挂载点（dc-host disk_usages 或尚未采集）'
  }
  return '暂无数据'
}

const diskTableColumns = [
  { title: '挂载点', dataIndex: 'mount', ellipsis: true, tooltip: true, width: 200 },
  { title: '类型', dataIndex: 'kindLabel', width: 120 },
  { title: '使用率', dataIndex: 'usedPercentLabel', width: 100 },
  { title: '总容量', dataIndex: 'totalLabel', width: 120 },
  { title: '已用', dataIndex: 'usedLabel', width: 120 },
  { title: '剩余', dataIndex: 'freeLabel', width: 120 },
]

/** 汇总接口 disk_root + data_disks 明细行 */
const diskTableRows = computed(() => {
  const d = summaryPayload.value
  if (!d?.has_data) return []
  const rows: Array<{
    mount: string
    kindLabel: string
    usedPercentLabel: string
    totalLabel: string
    usedLabel: string
    freeLabel: string
  }> = []
  const root = d.disk_root
  if (root && root.total_bytes > 0) {
    const freeBytes = root.free_bytes ?? Math.max(0, root.total_bytes - root.used_bytes)
    rows.push({
      mount: root.mount || '/',
      kindLabel: '系统盘（根）',
      usedPercentLabel: formatPercent(root.used_percent),
      totalLabel: formatBytes(root.total_bytes),
      usedLabel: formatBytes(root.used_bytes),
      freeLabel: formatBytes(freeBytes),
    })
  }
  const sorted = [...(d.data_disks ?? [])].sort((a, b) => (a.mount || '').localeCompare(b.mount || '', undefined, { sensitivity: 'base' }))
  for (const disk of sorted) {
    if (!disk.mount || disk.total_bytes <= 0) continue
    const freeBytes = disk.free_bytes ?? Math.max(0, disk.total_bytes - disk.used_bytes)
    rows.push({
      mount: disk.mount,
      kindLabel: '本地挂载',
      usedPercentLabel: formatPercent(disk.used_percent),
      totalLabel: formatBytes(disk.total_bytes),
      usedLabel: formatBytes(disk.used_bytes),
      freeLabel: formatBytes(freeBytes),
    })
  }
  return rows
})

function formatBytes(n: number | undefined | null): string {
  if (n === undefined || n === null || n <= 0) return '-'
  const units = ['B', 'KB', 'MB', 'GB', 'TB']
  let i = 0
  let x = n
  while (x >= 1024 && i < units.length - 1) {
    x /= 1024
    i += 1
  }
  const digits = i === 0 ? 0 : x >= 10 ? 1 : 2
  return `${x.toFixed(digits)} ${units[i]}`
}

const resourcePanels = computed<OsResourcePanel[]>(() => {
  const d = summaryPayload.value
  if (!d || !d.has_data) {
    return defaultResourcePanels
  }

  const mem = d.memory
  let memPanel: OsResourcePanel
  if (mem && mem.total_bytes > 0) {
    const freeBytes = mem.free_bytes ?? Math.max(0, mem.total_bytes - mem.used_bytes)
    memPanel = {
      key: 'memory',
      title: '内存',
      remaining: formatBytes(freeBytes),
      hasData: true,
      totalLabel: formatBytes(mem.total_bytes),
      usedLabel: formatBytes(mem.used_bytes),
      freeLabel: formatBytes(freeBytes),
      pieOptions: buildPieOptionsBytes(mem.used_bytes, freeBytes, '#165DFF'),
    }
  } else {
    memPanel = { ...defaultResourcePanels[0] }
  }

  const root = d.disk_root
  let sysPanel: OsResourcePanel
  if (root && root.total_bytes > 0) {
    const freeBytes = root.free_bytes ?? Math.max(0, root.total_bytes - root.used_bytes)
    const rootTitle = root.mount ? `磁盘（${root.mount}）` : '磁盘（系统盘 /）'
    sysPanel = {
      key: 'systemDisk',
      title: rootTitle,
      remaining: formatBytes(freeBytes),
      hasData: true,
      totalLabel: formatBytes(root.total_bytes),
      usedLabel: formatBytes(root.used_bytes),
      freeLabel: formatBytes(freeBytes),
      pieOptions: buildPieOptionsBytes(root.used_bytes, freeBytes, '#14C9C9'),
    }
  } else {
    sysPanel = { ...defaultResourcePanels[1] }
  }

  const cores = d.cpu?.physical_threads_total ?? d.cpu?.logical_cores_total ?? 0
  const usage = d.cpu?.usage_percent ?? 0
  const usedCores = cores > 0 ? (usage / 100) * cores : 0
  const freeCores = cores > 0 ? Math.max(0, cores - usedCores) : 0
  let cpuPanel: OsResourcePanel
  if (cores > 0) {
    cpuPanel = {
      key: 'cpu',
      title: 'CPU',
      remaining: `${round1(freeCores)} 核`,
      hasData: true,
      totalLabel: `${round1(cores)} 核`,
      usedLabel: `约 ${round1(usedCores)} 核`,
      freeLabel: `${round1(freeCores)} 核`,
      pieOptions: buildPieOptionsCores(usedCores, freeCores, '#00B42A'),
    }
  } else {
    cpuPanel = { ...defaultResourcePanels[2] }
  }

  const disks = d.data_disks
  let aggTotal = 0
  let aggUsed = 0
  let aggFree = 0
  if (disks?.length) {
    for (const disk of disks) {
      aggTotal += disk.total_bytes
      aggUsed += disk.used_bytes
      aggFree += disk.free_bytes ?? Math.max(0, disk.total_bytes - disk.used_bytes)
    }
  }
  let dataPanel: OsResourcePanel
  if (aggTotal > 0) {
    const freeBytes = aggFree > 0 ? aggFree : Math.max(0, aggTotal - aggUsed)
    const list = disks ?? []
    const n = list.length
    const dataTitle = n === 1 ? `硬盘（${list[0].mount}）` : n > 1 ? `本地挂载（${n} 个挂载点汇总）` : '硬盘（数据盘汇总）'
    dataPanel = {
      key: 'dataDisk',
      title: dataTitle,
      remaining: formatBytes(freeBytes),
      hasData: true,
      totalLabel: formatBytes(aggTotal),
      usedLabel: formatBytes(aggUsed),
      freeLabel: formatBytes(freeBytes),
      pieOptions: buildPieOptionsBytes(aggUsed, freeBytes, '#722ED1'),
    }
  } else {
    dataPanel = { ...defaultResourcePanels[3] }
  }

  return [memPanel, sysPanel, cpuPanel, dataPanel]
})

function filterServerOption(input: string, option: { label?: string }) {
  if (!input) return true
  const q = input.trim().toLowerCase()
  const label = String(option?.label ?? '').toLowerCase()
  return label.includes(q)
}

function formatAlertTime(iso: string | undefined | null) {
  if (!iso) return '-'
  return dayjs(iso).format('MM-DD HH:mm')
}

function alertStatusColor(status: string | undefined) {
  const map: Record<string, string> = {
    firing: 'red',
    pending: 'orange',
    acked: 'gold',
    resolved: 'green',
    silenced: 'gray',
    suppressed: 'lightgray',
  }
  return map[status || ''] || 'blue'
}

function alertStatusText(status: string | undefined) {
  const map: Record<string, string> = {
    firing: '告警中',
    pending: '待处理',
    acked: '已确认',
    resolved: '已解决',
    silenced: '已屏蔽',
    suppressed: '已抑制',
  }
  return map[status || ''] || status || '-'
}

/**
 * 从 Alert/v1/record/list 的 details 中解析列表（兼容 data / list / records）
 */
function normalizeAlertRecordList(res: any): any[] {
  const d = res?.details
  if (!d) return []
  const raw = d.data ?? d.list ?? d.records
  return Array.isArray(raw) ? raw : []
}

async function loadRecentAlertsForServer(server: ServerOption | undefined) {
  if (!server) {
    recentAlerts.value = []
    return
  }
  const targetSid = server.server_identity
  try {
    const res: any = await fetchAlertRecords({
      page: 1,
      page_size: 5,
      sort: 'starts_at',
      order: 'desc',
      server_identity: targetSid,
    })
    /** 切换主机后丢弃过期响应，避免空结果仍显示上一台主机的列表 */
    if (selectedServerIdentity.value !== targetSid) {
      return
    }
    const code = res?.code
    const codeOk = code === undefined || code === null || code === 0 || code === '0'
    if (!codeOk) {
      recentAlerts.value = []
      Message.error(res.message || '加载最近告警失败')
      return
    }
    const rows = normalizeAlertRecordList(res).slice(0, 5)
    recentAlerts.value = rows
  } catch (e: any) {
    if (selectedServerIdentity.value === targetSid) {
      recentAlerts.value = []
      Message.error(e?.message || '加载最近告警失败')
    }
  }
}

/** 是否已有速率曲线数据（兼容旧接口仅看 points） */
const hasTrafficRateSeries = computed(() => {
  const p = trafficPayload.value
  if (!p) return false
  if (typeof p.has_rate_series === 'boolean') return p.has_rate_series
  return (p.points?.length ?? 0) > 0
})

const trafficHint = computed(() => {
  const p = trafficPayload.value
  if (!p || chartLoading.value) return ''
  if (hasTrafficRateSeries.value) return ''
  if (p.has_data) {
    return p.note || '已有指标，需至少两次采集后才展示速率曲线'
  }
  return '暂无主机网络累计指标（control_host_metrics_data），请确认主机采集与落库。'
})

const trafficChartOptions = computed(() => {
  const pts = trafficPayload.value?.points ?? []
  if (!pts.length) {
    return {
      tooltip: { trigger: 'axis' },
      legend: { show: false },
      grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
      xAxis: { type: 'category', boundaryGap: false, data: ['-'] },
      yAxis: { type: 'value', name: 'Mb/s' },
      series: [
        {
          name: '接收',
          type: 'line',
          smooth: true,
          data: [0],
          lineStyle: { width: 2, color: '#165DFF' },
          itemStyle: { color: '#165DFF' },
        },
        {
          name: '发送',
          type: 'line',
          smooth: true,
          data: [0],
          lineStyle: { width: 2, color: '#14C9C9' },
          itemStyle: { color: '#14C9C9' },
        },
      ],
    }
  }
  const labels = pts.map((p) => dayjs(p.time).format('MM-DD HH:mm'))
  const rx = pts.map((p) => round1(p.recv_mbps))
  const tx = pts.map((p) => round1(p.send_mbps))
  return {
    tooltip: { trigger: 'axis' },
    legend: { show: false },
    grid: {
      left: '3%',
      right: '4%',
      bottom: '3%',
      containLabel: true,
    },
    xAxis: {
      type: 'category',
      boundaryGap: false,
      data: labels,
    },
    yAxis: {
      type: 'value',
      name: 'Mb/s',
    },
    series: [
      {
        name: '接收',
        type: 'line',
        smooth: true,
        data: rx,
        areaStyle: { opacity: 0.08 },
        lineStyle: { width: 2, color: '#165DFF' },
        itemStyle: { color: '#165DFF' },
      },
      {
        name: '发送',
        type: 'line',
        smooth: true,
        data: tx,
        areaStyle: { opacity: 0.08 },
        lineStyle: { width: 2, color: '#14C9C9' },
        itemStyle: { color: '#14C9C9' },
      },
    ],
  }
})

async function loadServerOptions() {
  serverListLoading.value = true
  try {
    const res: any = await fetchServerList({ page: 1, size: 500 })
    if (res.code !== 0) {
      Message.error(res.message || '加载服务器列表失败')
      serverOptions.value = []
      return
    }
    const list: ServerItem[] = res.details?.data ?? []
    serverOptions.value = list.map((r) => ({
      server_identity: r.server_identity,
      name: r.name,
      host: r.host,
      ip: r.ip_address || r.host,
      os: [r.os, r.os_version].filter(Boolean).join(' ') || '-',
      location: r.location || '-',
    }))
    if (selectedServerIdentity.value && !serverOptions.value.some((s) => s.server_identity === selectedServerIdentity.value)) {
      selectedServerIdentity.value = undefined
    }
    if (!selectedServerIdentity.value && serverOptions.value.length > 0) {
      selectedServerIdentity.value = serverOptions.value[0].server_identity
    }
  } catch (e: any) {
    Message.error(e?.message || '加载服务器列表失败')
    serverOptions.value = []
  } finally {
    serverListLoading.value = false
  }
}

async function refreshDashboard() {
  const sid = selectedServerIdentity.value
  if (!sid) {
    summaryPayload.value = null
    trafficPayload.value = null
    recentAlerts.value = []
    return
  }
  const server = serverOptions.value.find((s) => s.server_identity === sid)
  statsLoading.value = true
  chartLoading.value = true
  alertsLoading.value = true
  recentAlerts.value = []
  try {
    const [sumRes, trafRes]: any[] = await Promise.all([
      fetchServerMetricsSummary(sid),
      fetchServerNetworkTraffic(sid, 6),
      loadRecentAlertsForServer(server),
    ])
    if (sumRes.code === 0) {
      summaryPayload.value = sumRes.details ?? null
    } else {
      summaryPayload.value = null
      Message.error(sumRes.message || '加载统计卡片失败')
    }
    if (trafRes.code === 0) {
      trafficPayload.value = trafRes.details ?? null
    } else {
      trafficPayload.value = null
      Message.error(trafRes.message || '加载网络流量失败')
    }
  } catch (e: any) {
    Message.error(e?.message || '请求失败')
    summaryPayload.value = null
    trafficPayload.value = null
    recentAlerts.value = []
  } finally {
    statsLoading.value = false
    chartLoading.value = false
    alertsLoading.value = false
  }
}

watch(selectedServerIdentity, (sid) => {
  if (!sid) {
    summaryPayload.value = null
    trafficPayload.value = null
    recentAlerts.value = []
    return
  }
  refreshDashboard()
})

onMounted(async () => {
  await loadServerOptions()
  // 首次选中由 loadServerOptions 设置，watch(selectedServerIdentity) 会拉取指标
})
</script>

<script lang="ts">
export default {
  name: 'OsMonitor',
}
</script>

<style scoped lang="less">
.container {
  padding: 16px;
}

.page-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
}

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

.toolbar-label {
  font-size: 14px;
  color: var(--color-text-2);
  white-space: nowrap;
}

.server-select {
  min-width: 260px;
  max-width: 360px;
}

.server-option {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
}

.server-option-name {
  font-size: 14px;
  color: var(--color-text-1);
}

.server-option-ip {
  font-size: 13px;
  color: var(--color-text-3);
  font-family: var(--font-family-mono);
}

.toolbar-meta {
  font-size: 13px;
}

.stats-row {
  margin-bottom: 16px;
}

.pie-row {
  margin-bottom: 16px;

  :deep(.arco-row) {
    align-items: stretch;
  }

  > .arco-col {
    display: flex;
  }
}

.disk-table-row {
  margin-bottom: 16px;
}

.pie-card {
  flex: 1;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;

  :deep(.arco-card-header) {
    border-bottom: none;
    padding-bottom: 0;
  }

  :deep(.arco-card-body) {
    flex: 1;
    display: flex;
    flex-direction: column;
    padding-top: 8px;
  }
}

.pie-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

/** 与有数据时 Chart 高度一致，避免同排卡片高低不齐 */
.pie-chart-slot {
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  width: 100%;
  height: 220px;
  min-height: 220px;
}

.pie-chart-slot--empty {
  background-color: var(--color-fill-1);
  border: 1px dashed var(--color-border-2);
  border-radius: 8px;
}

.pie-empty-inner {
  padding: 0;
}

.pie-meta {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  margin-top: 8px;
  min-height: 36px;
  font-size: 12px;
  line-height: 1.5;
  text-align: center;
}

.pie-meta-placeholder {
  display: inline-block;
  opacity: 0;
  pointer-events: none;
}

.stats-card {
  height: 100%;

  :deep(.arco-card-body) {
    padding: 16px;
  }

  .stats-content {
    display: flex;
    align-items: flex-start;
    gap: 12px;
  }

  .stats-icon {
    width: 48px;
    height: 48px;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 24px;

    &-primary {
      background-color: rgba(22, 93, 255, 0.1);
      color: rgb(var(--primary-6));
    }

    &-cyan {
      background-color: rgba(20, 201, 201, 0.1);
      color: #14c9c9;
    }

    &-green {
      background-color: rgba(0, 180, 42, 0.1);
      color: rgb(var(--success-6));
    }

    &-purple {
      background-color: rgba(114, 46, 209, 0.1);
      color: #722ed1;
    }
  }

  .stats-info {
    flex: 1;
    min-width: 0;
  }

  .stats-title {
    font-size: 14px;
    color: var(--color-text-3);
    margin-bottom: 4px;
  }

  .stats-value {
    font-size: 24px;
    font-weight: 600;
    color: var(--color-text-1);
    line-height: 1.2;
    margin-bottom: 4px;
  }

  .stats-desc {
    font-size: 12px;
    color: var(--color-text-3);
    line-height: 1.5;
  }
}

.chart-row {
  margin-bottom: 16px;

  :deep(.arco-row) {
    align-items: stretch;
  }

  > .arco-col {
    display: flex;
  }

  > .arco-col > .arco-card {
    flex: 1;
    width: 100%;
    display: flex;
    flex-direction: column;

    :deep(.arco-card-body) {
      flex: 1;
      display: flex;
      flex-direction: column;
    }
  }
}

.chart-container {
  height: 300px;
  min-height: 300px;
}

.legend-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--color-text-3);
}

.legend-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;

  &-1 {
    background-color: #165dff;
  }

  &-2 {
    background-color: #14c9c9;
  }
}

.chart-spin {
  display: flex;
  flex-direction: column;
  flex: 1;
  width: 100%;
  min-width: 0;
}

.alert-spin {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  width: 100%;
}

.alert-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.alert-item {
  padding: 10px 12px;
  border-radius: 8px;
  background: var(--color-fill-1);
  border: 1px solid var(--color-border-1);
}

.alert-item-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 6px;
}

.alert-item-name {
  font-size: 14px;
  font-weight: 500;
  color: var(--color-text-1);
  line-height: 1.4;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.alert-item-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 4px;
}

.alert-item-time {
  font-size: 12px;
  color: var(--color-text-3);
}

.alert-item-summary {
  font-size: 12px;
  line-height: 1.5;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.alert-empty-wrap {
  display: flex;
  flex: 1;
  align-items: center;
  justify-content: center;
  min-height: 300px;
  box-sizing: border-box;
}

.text-muted {
  font-size: 12px;
  color: var(--color-text-3);
}
</style>
