<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="loading" style="width: 100%">
      <div v-if="!selectedServerIdentity" class="hw-empty">
        <a-empty description="请先选择服务器" />
      </div>

      <div v-else-if="notConfigured" class="hw-empty">
        <a-empty :description="notConfiguredHint">
          <template v-if="hardwareError" #extra>
            <span class="text-muted">{{ hardwareError }}</span>
          </template>
        </a-empty>
      </div>

      <template v-else>
        <a-alert v-if="statusSnapshot?.error_message" type="warning" :title="statusSnapshot.error_message" style="margin-bottom: 16px" />

        <a-card title="带外设备与采集摘要" :bordered="false" class="hw-card">
          <a-descriptions :column="{ xs: 1, sm: 2, md: 3 }" size="small" layout="horizontal">
            <a-descriptions-item label="设备名称">
              {{ deviceMeta?.name || '-' }}
            </a-descriptions-item>
            <a-descriptions-item label="管理 IP">
              {{ deviceMeta?.ip || '-' }}
            </a-descriptions-item>
            <a-descriptions-item label="协议">
              {{ deviceMeta?.protocol || '-' }}
            </a-descriptions-item>
            <a-descriptions-item label="类型">
              {{ deviceTypeLabel(deviceMeta?.type) }}
            </a-descriptions-item>
            <a-descriptions-item label="厂商">
              {{ deviceMeta?.manufacturer || '—' }}
            </a-descriptions-item>
            <a-descriptions-item label="型号">
              {{ deviceMeta?.model || '—' }}
            </a-descriptions-item>
            <a-descriptions-item label="序列号">
              {{ deviceMeta?.serial_number || '—' }}
            </a-descriptions-item>
            <a-descriptions-item label="采集间隔(秒)">
              {{ intervalLabel }}
            </a-descriptions-item>
            <a-descriptions-item label="启用">
              <a-tag v-if="deviceMeta" size="small" :color="deviceMeta.enabled ? 'green' : 'red'">
                {{ deviceMeta.enabled ? '是' : '否' }}
              </a-tag>
              <span v-else>—</span>
            </a-descriptions-item>
            <a-descriptions-item label="最近采集时间">
              {{ collectedAtLabel }}
            </a-descriptions-item>
            <a-descriptions-item label="整体健康">
              <a-tag v-if="statusSnapshot?.status" size="small" :color="healthColor(statusSnapshot.status)">
                {{ statusSnapshot.status }}
              </a-tag>
              <span v-else>—</span>
            </a-descriptions-item>
            <a-descriptions-item label="时序库">
              <a-tag size="small" :color="timescaledb ? 'arcoblue' : 'gray'">
                {{ timescaledb ? '已配置' : '未配置' }}
              </a-tag>
            </a-descriptions-item>
          </a-descriptions>
        </a-card>

        <a-card title="健康分项" :bordered="false" class="hw-card">
          <a-row :gutter="[12, 12]">
            <a-col v-for="item in subStatusItems" :key="item.key" :xs="12" :sm="8" :md="6" :lg="4">
              <div class="hw-sub-item">
                <div class="hw-sub-label">{{ item.label }}</div>
                <a-tag v-if="item.value" size="small" :color="healthColor(item.value)">
                  {{ item.value }}
                </a-tag>
                <span v-else class="hw-sub-dash">—</span>
              </div>
            </a-col>
          </a-row>
        </a-card>

        <a-card v-if="statisticsSummary" title="近 7 日汇总（最新日）" :bordered="false" class="hw-card">
          <a-row :gutter="16">
            <a-col v-for="cell in statisticsSummary" :key="cell.label" :xs="12" :sm="8" :md="6">
              <div class="hw-stat-cell">
                <div class="hw-stat-label">{{ cell.label }}</div>
                <div class="hw-stat-value">{{ cell.value }}</div>
              </div>
            </a-col>
          </a-row>
        </a-card>

        <template v-if="groupedMetrics.length">
          <a-card v-for="g in groupedMetrics" :key="g.type" :title="g.title" :bordered="false" class="hw-card">
            <a-table :columns="metricColumns" :data="g.rows" :pagination="false" row-key="__key" size="small" :bordered="{ cell: true }">
              <template #status="{ record }">
                <a-tag size="small" :color="healthColor(record.status)">
                  {{ record.status || '—' }}
                </a-tag>
              </template>
            </a-table>
          </a-card>
        </template>
        <a-card v-else title="指标明细" :bordered="false" class="hw-card">
          <a-empty description="暂无指标数据（请确认采集成功或查看原始 JSON）" />
        </a-card>

        <a-card v-if="timescaledb && deviceId && metricNameOptions.length" title="单指标趋势" :bordered="false" class="hw-card">
          <div class="hw-chart-toolbar">
            <a-select
              v-model="selectedMetricName"
              allow-search
              :style="{ width: '280px' }"
              placeholder="选择指标"
              :options="metricNameOptions"
            />
            <span class="text-muted">默认最近 24 小时</span>
          </div>
          <a-spin :loading="historyLoading" style="width: 100%">
            <div class="hw-chart-wrap">
              <Chart v-if="historyChartOptions" :options="historyChartOptions" height="280px" width="100%" />
              <a-empty v-else description="暂无曲线数据" />
            </div>
          </a-spin>
        </a-card>
        <a-card v-else-if="deviceId && !timescaledb" title="单指标趋势" :bordered="false" class="hw-card">
          <p class="text-muted">未配置 TimescaleDB，时序曲线不可用；可查看上方指标表或下方原始 JSON。</p>
        </a-card>

        <a-card title="原始采集 JSON" :bordered="false" class="hw-card">
          <a-collapse>
            <a-collapse-item key="raw" header="展开查看 raw_data（排障）">
              <pre class="hw-raw-pre">{{ rawDataFormatted }}</pre>
            </a-collapse-item>
          </a-collapse>
        </a-card>
      </template>
    </a-spin>
  </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 Chart from '@/components/chart/index.vue'
import { fetchServerList, type ServerItem } from '@/api/ops/server'
import {
  fetchHostHardwareDevice,
  fetchHostHardwareLatestCollection,
  fetchHostHardwareMetricHistory,
  fetchHostHardwareStatistics,
  isHostHardwareApiSuccess,
  normalizeHostHardwareMetrics,
  unwrapHostHardwareDetails,
  type HostHardwareDevice,
  type HostHardwareLatestCollectionPayload,
  type HostHardwareStatisticsRow,
  type HostHardwareStatus,
  type NormalizedHostHardwareMetric,
} from '@/api/ops/host-hardware'

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

const serverListLoading = ref(false)
const loading = ref(false)
const notConfigured = ref(false)
const hardwareError = ref('')
const collection = ref<HostHardwareLatestCollectionPayload | null>(null)
const deviceMeta = ref<HostHardwareDevice | null>(null)
const historyLoading = ref(false)
const statisticsRows = ref<HostHardwareStatisticsRow[]>([])
const selectedMetricName = ref<string>('')
const historyChartOptions = ref<Record<string, unknown> | null>(null)

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

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

/** 与 hardware_devices.type 一致：server/switch/storage 等 */
function deviceTypeLabel(t?: string) {
  if (t === undefined || t === null || String(t).trim() === '') return '—'
  const raw = String(t).trim()
  const map: Record<string, string> = {
    server: '服务器',
    switch: '交换机',
    storage: '存储',
    other: '其它',
  }
  return map[raw] || raw
}

const statusSnapshot = computed(() => collection.value?.status ?? null)
const deviceId = computed(() => collection.value?.device_id ?? '')
const timescaledb = computed(() => collection.value?.timescaledb === true)

const normalizedMetrics = computed<NormalizedHostHardwareMetric[]>(() =>
  normalizeHostHardwareMetrics(statusSnapshot.value, collection.value?.metrics)
)

const metricNameOptions = computed(() => {
  const names = [...new Set(normalizedMetrics.value.map((m) => m.name).filter(Boolean))]
  return names.sort().map((n) => ({ label: n, value: n }))
})

const collectedAtLabel = computed(() => {
  const t = collection.value?.collected_at || statusSnapshot.value?.last_check_time
  if (!t) return '—'
  return dayjs(t).format('YYYY-MM-DD HH:mm:ss')
})

const intervalLabel = computed(() => {
  const n = deviceMeta.value?.collect_interval
  if (n === undefined || n === null) return '—'
  if (n <= 0) return '默认（服务端 YAML）'
  return String(n)
})

const notConfiguredHint = computed(() => {
  if (hardwareError.value) return '无法加载服务器硬件监控数据'
  return '未配置带外监控：请在 DC-Hardware 中创建设备并填写与当前主机一致的 server_identity'
})

const subStatusItems = computed(() => {
  const s = statusSnapshot.value
  const fields: { key: keyof HostHardwareStatus; label: string }[] = [
    { key: 'power_status', label: '电源' },
    { key: 'temperature_status', label: '温度' },
    { key: 'fan_status', label: '风扇' },
    { key: 'psu_status', label: 'PSU' },
    { key: 'cpu_status', label: 'CPU' },
    { key: 'memory_status', label: '内存' },
    { key: 'disk_status', label: '磁盘' },
  ]
  return fields.map((f) => ({
    key: String(f.key),
    label: f.label,
    value: (s?.[f.key] as string | undefined) || '',
  }))
})

const GROUP_ORDER = ['temperature', 'fan_speed', 'voltage', 'current', 'power', 'power_status', 'network', 'system', 'uptime']

function groupTitle(t: string): string {
  const map: Record<string, string> = {
    temperature: '温度',
    fan_speed: '风扇',
    voltage: '电压',
    current: '电流',
    power: '功耗',
    power_status: '电源状态',
    network: '网络',
    system: '系统',
    uptime: '运行时间',
    other: '其它',
  }
  return map[t] || t || '其它'
}

const groupedMetrics = computed(() => {
  const rows = normalizedMetrics.value
  const map = new Map<string, NormalizedHostHardwareMetric[]>()
  for (const r of rows) {
    const t = r.type || 'other'
    const list = map.get(t) ?? []
    list.push(r)
    map.set(t, list)
  }
  const keys = [...map.keys()].sort((a, b) => {
    const ia = GROUP_ORDER.indexOf(a)
    const ib = GROUP_ORDER.indexOf(b)
    if (ia === -1 && ib === -1) return a.localeCompare(b)
    if (ia === -1) return 1
    if (ib === -1) return -1
    return ia - ib
  })
  return keys.map((k) => ({
    type: k,
    title: groupTitle(k),
    rows: map.get(k)!.map((m, idx) => ({
      __key: `${k}-${idx}-${m.name}-${m.location ?? ''}`,
      name: m.name,
      type: m.type,
      value: formatMetricValue(m.value),
      unit: m.unit || '—',
      location: m.location || '—',
      threshold: m.threshold !== undefined && m.threshold !== 0 ? String(m.threshold) : '—',
      status: m.status,
    })),
  }))
})

const metricColumns = [
  { title: '名称', dataIndex: 'name', ellipsis: true, tooltip: true, width: 200 },
  { title: '类型', dataIndex: 'type', width: 120 },
  { title: '位置', dataIndex: 'location', ellipsis: true, width: 140 },
  { title: '数值', dataIndex: 'value', width: 120 },
  { title: '单位', dataIndex: 'unit', width: 80 },
  { title: '阈值', dataIndex: 'threshold', width: 110 },
  { title: '状态', dataIndex: 'status', width: 100, slotName: 'status' },
]

function formatMetricValue(v: number): string {
  if (Number.isInteger(v)) return String(v)
  if (Number.isNaN(v)) return '-'
  return v.toFixed(2)
}

function healthColor(s: string): string {
  const x = (s || '').toLowerCase()
  if (x === 'ok' || x === 'online' || x === 'on') return 'green'
  if (x === 'warning') return 'orange'
  if (x === 'critical' || x === 'offline' || x === 'error') return 'red'
  if (x === 'unknown') return 'gray'
  return 'arcoblue'
}

const rawDataFormatted = computed(() => {
  const raw = statusSnapshot.value?.raw_data
  if (!raw) return '—'
  try {
    const o = JSON.parse(raw)
    return JSON.stringify(o, null, 2)
  } catch {
    return raw
  }
})

const statisticsSummary = computed(() => {
  const rows = statisticsRows.value
  if (!rows.length) return null
  const latest = [...rows].sort((a, b) => {
    const ta = new Date(a.stat_date).getTime()
    const tb = new Date(b.stat_date).getTime()
    return tb - ta
  })[0]
  const cells: { label: string; value: string }[] = []
  const push = (label: string, v: number | undefined) => {
    if (v === undefined || v === null || Number.isNaN(v)) return
    cells.push({ label, value: String(v) })
  }
  push('平均温度', latest.avg_temperature)
  push('最高温度', latest.max_temperature)
  push('最低温度', latest.min_temperature)
  push('平均风扇转速', latest.avg_fan_speed)
  push('平均功耗', latest.avg_power_usage)
  push('最大功耗', latest.max_power_usage)
  push('可用率(%)', latest.availability)
  push('告警次数', latest.warning_count)
  push('严重次数', latest.critical_count)
  return cells.length ? cells : null
})

async function loadStatistics(id: string) {
  try {
    const end = dayjs().format('YYYY-MM-DD')
    const start = dayjs().subtract(6, 'day').format('YYYY-MM-DD')
    const res = await fetchHostHardwareStatistics(id, start, end)
    const rows = unwrapHostHardwareDetails(res)
    statisticsRows.value = Array.isArray(rows) ? rows : []
  } catch {
    statisticsRows.value = []
  }
}

async function loadHistory() {
  const id = deviceId.value
  const name = selectedMetricName.value
  if (!id || !name || !timescaledb.value) {
    historyChartOptions.value = null
    return
  }
  historyLoading.value = true
  try {
    const end = dayjs()
    const start = end.subtract(24, 'hour')
    const res = await fetchHostHardwareMetricHistory(id, name, start.toISOString(), end.toISOString())
    const payload = unwrapHostHardwareDetails(res)
    const points = payload?.data ?? []
    if (!points.length) {
      historyChartOptions.value = null
      return
    }
    const labels = points.map((p) => dayjs(p.collection_time).format('MM-DD HH:mm'))
    const vals = points.map((p) => p.metric_value / 100)
    historyChartOptions.value = {
      tooltip: { trigger: 'axis' },
      grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
      xAxis: { type: 'category', boundaryGap: false, data: labels },
      yAxis: { type: 'value', name: points[0]?.unit || '' },
      series: [
        {
          name,
          type: 'line',
          smooth: true,
          data: vals,
          lineStyle: { width: 2, color: '#165DFF' },
          itemStyle: { color: '#165DFF' },
        },
      ],
    }
  } catch {
    historyChartOptions.value = null
  } finally {
    historyLoading.value = false
  }
}

function resetState() {
  notConfigured.value = false
  hardwareError.value = ''
  collection.value = null
  deviceMeta.value = null
  statisticsRows.value = []
  historyChartOptions.value = null
  selectedMetricName.value = ''
}

async function loadHostHardware() {
  const sid = selectedServerIdentity.value
  if (!sid) {
    resetState()
    return
  }
  loading.value = true
  hardwareError.value = ''
  try {
    const res = await fetchHostHardwareLatestCollection(sid)
    if (!isHostHardwareApiSuccess(res)) {
      notConfigured.value = true
      collection.value = null
      deviceMeta.value = null
      hardwareError.value = (res as { message?: string })?.message || ''
      return
    }
    const data = unwrapHostHardwareDetails(res)
    if (!data) {
      notConfigured.value = true
      return
    }
    notConfigured.value = false
    collection.value = data
    if (data.device_id) {
      const devRes = await fetchHostHardwareDevice(data.device_id)
      if (isHostHardwareApiSuccess(devRes)) {
        const devPayload = unwrapHostHardwareDetails(devRes)
        deviceMeta.value = devPayload?.device ?? null
      } else {
        deviceMeta.value = null
      }
      await loadStatistics(data.device_id)
    } else {
      deviceMeta.value = null
      statisticsRows.value = []
    }
    const names = [
      ...new Set(
        normalizeHostHardwareMetrics(data.status, data.metrics)
          .map((m) => m.name)
          .filter(Boolean)
      ),
    ]
    selectedMetricName.value = names.sort()[0] || ''
  } catch (e: unknown) {
    const err = e as { response?: { data?: { message?: string } }; message?: string }
    notConfigured.value = true
    collection.value = null
    deviceMeta.value = null
    hardwareError.value = err?.response?.data?.message || err?.message || '请求失败'
  } finally {
    loading.value = false
  }
}

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

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
  }
}

watch(
  selectedServerIdentity,
  () => {
    loadHostHardware()
  },
  { immediate: true }
)

watch([selectedMetricName, timescaledb, deviceId], () => {
  loadHistory()
})

onMounted(async () => {
  await loadServerOptions()
})
</script>

<script lang="ts">
export default {
  name: 'ServerHardwareMonitor',
}
</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;
}

.hw-empty {
  min-height: 220px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.hw-card {
  margin-bottom: 16px;
}

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

.hw-sub-label {
  font-size: 12px;
  color: var(--color-text-3);
  margin-bottom: 6px;
}

.hw-sub-dash {
  color: var(--color-text-4);
  font-size: 13px;
}

.hw-stat-cell {
  padding: 12px;
  border-radius: 8px;
  background: var(--color-fill-1);
  border: 1px solid var(--color-border-1);
}

.hw-stat-label {
  font-size: 12px;
  color: var(--color-text-3);
  margin-bottom: 4px;
}

.hw-stat-value {
  font-size: 18px;
  font-weight: 600;
  color: var(--color-text-1);
}

.hw-chart-toolbar {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 12px;
  flex-wrap: wrap;
}

.hw-chart-wrap {
  width: 100%;
  min-height: 280px;
}

.hw-raw-pre {
  margin: 0;
  max-height: 360px;
  overflow: auto;
  font-size: 12px;
  line-height: 1.45;
  white-space: pre-wrap;
  word-break: break-all;
}

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