<template>
  <div class="server-inline-detail pa-3 rounded-b-lg">
    <ServerAgentHint
      class="mb-3"
      :action="displayServer.agent_action"
      :message="displayServer.agent_action_message"
      :loading="props.agentActionLoading"
      @install="$emit('install-agent')"
      @upgrade="$emit('upgrade-agent')"
      @diagnose="$emit('diagnose-agent')"
    />

    <div class="d-flex flex-wrap align-center ga-2 mb-3">
      <v-chip
        :color="statusChipColor(displayServer.status)"
        size="x-small"
        variant="tonal"
        label
        border="sm"
      >
        {{ statusLabel(displayServer.status) }}
      </v-chip>
      <span class="text-caption text-medium-emphasis">
        心跳 {{ formatRelativeTime(displayServer.last_heartbeat) }}
      </span>
      <v-spacer />
      <v-btn
        v-if="refreshError"
        variant="text"
        size="x-small"
        color="primary"
        :loading="refreshing"
        @click="() => refreshAll()"
      >
        重试
      </v-btn>
    </div>

    <v-skeleton-loader v-if="refreshing && !detail" type="article" class="mb-3" />

    <div v-else class="d-flex flex-wrap ga-4 mb-3 text-body-2">
      <div>
        <span class="text-caption text-medium-emphasis">CPU</span>
        {{ displayServer.system_info?.cpu_usage ?? '—' }}%
      </div>
      <div>
        <span class="text-caption text-medium-emphasis">内存</span>
        {{ displayServer.system_info?.mem_usage ?? '—' }}%
      </div>
      <div>
        <span class="text-caption text-medium-emphasis">磁盘</span>
        {{ displayServer.system_info?.disk_usage ?? '—' }}%
      </div>
      <div>
        <span class="text-caption text-medium-emphasis">Agent</span>
        {{ displayServer.agent_version || '未安装' }}
      </div>
    </div>

    <div v-if="refreshError && detail" class="text-caption text-warning mb-2">
      实时数据可能滞后：{{ refreshError }}
    </div>

    <ServerMetricSparklines
      class="mb-3"
      :points="metricPoints"
      :offline-segments="offlineSegments"
      :interval-minutes="metricIntervalMinutes"
      :loading="metricsLoading"
      :error="metricsError"
      @retry="() => { const id = ++requestId; void loadMetrics(id) }"
    />

    <div class="d-flex align-center ga-2 mb-2">
      <span class="text-caption text-medium-emphasis shrink-0">目标路径</span>
      <span class="text-body-2 text-truncate">
        {{ displayServer.target_path?.trim() || '未配置（推送页留空时无法推送到此机）' }}
      </span>
      <v-btn
        icon="mdi-pencil"
        size="x-small"
        variant="text"
        density="compact"
        title="编辑目标路径"
        @click.stop="$emit('edit-path')"
      />
    </div>

    <div class="text-caption text-medium-emphasis mb-1">同步日志</div>
    <v-skeleton-loader v-if="logsLoading" type="list-item-two-line" />
    <div v-else-if="logsError" class="text-caption text-error py-1">{{ logsError }}</div>
    <div v-else-if="!latestLog" class="text-caption text-medium-emphasis py-1">暂无同步日志</div>
    <v-list-item
      v-else
      density="compact"
      class="bg-transparent pa-0"
      :subtitle="formatSyncLogTime(latestLog)"
      :title="`${latestLog.source_path} → ${latestLog.target_path}`"
    >
      <template #append>
        <v-chip size="x-small" :color="syncLogStatusColor(latestLog.status)" variant="tonal" label>
          {{ syncLogStatusLabel(latestLog.status) }}
        </v-chip>
      </template>
    </v-list-item>
  </div>
</template>

<script setup lang="ts">
import { computed, ref, watch, onBeforeUnmount } from 'vue'
import { http } from '@/api'
import { formatPushPermission } from '@/composables/push/labels'
import { formatApiError } from '@/utils/apiError'
import { statusChipColor, statusLabel, formatRelativeTime } from '@/utils/status'
import type {
  PushItem,
  ServerApiItem,
  ServerMetricOfflineSegment,
  ServerMetricPoint,
  ServerMetricsResponse,
} from '@/types/api'
import { formatDateTimeBeijing } from '@/utils/datetime'
import ServerMetricSparklines from '@/components/servers/ServerMetricSparklines.vue'
import ServerAgentHint from '@/components/servers/ServerAgentHint.vue'

const props = defineProps<{
  server: ServerApiItem
  active?: boolean
  agentActionLoading?: boolean
}>()

defineEmits<{
  'edit-path': []
  'install-agent': []
  'upgrade-agent': []
  'diagnose-agent': []
}>()

const detail = ref<ServerApiItem | null>(null)
const refreshing = ref(false)
const refreshError = ref('')

const logsLoading = ref(false)
const logsError = ref('')
const latestLog = ref<PushItem | null>(null)

const metricsLoading = ref(false)
const metricsError = ref('')
const metricPoints = ref<ServerMetricPoint[]>([])
const offlineSegments = ref<ServerMetricOfflineSegment[]>([])
const metricIntervalMinutes = ref(10)

let requestId = 0

const displayServer = computed(() => detail.value ?? props.server)

function syncLogStatusColor(status: string): string {
  switch (status) {
    case 'success': return 'success'
    case 'failed': return 'error'
    case 'running': return 'warning'
    case 'cancelled': return 'grey'
    default: return 'default'
  }
}

function syncLogStatusLabel(status: string): string {
  switch (status) {
    case 'success': return '成功'
    case 'failed': return '失败'
    case 'running': return '进行中'
    case 'cancelled': return '已取消'
    default: return status
  }
}

function formatSyncLogTime(log: PushItem): string {
  const parts: string[] = []
  if (log.started_at) parts.push(formatDateTimeBeijing(log.started_at))
  if (log.sync_mode) parts.push(log.sync_mode)
  if (log.trigger_type) parts.push(log.trigger_type)
  if (log.push_permission) parts.push(`权限 ${formatPushPermission(log.push_permission)}`)
  return parts.join(' · ') || '—'
}

function parseServerSyncLogs(res: unknown): PushItem[] {
  if (Array.isArray(res)) return res as PushItem[]
  if (res && typeof res === 'object' && Array.isArray((res as { items?: unknown }).items)) {
    return (res as { items: PushItem[] }).items
  }
  return []
}

async function loadDetail(myId: number) {
  try {
    const res = await http.get<ServerApiItem>(`/servers/${props.server.id}`)
    if (myId !== requestId) return
    detail.value = res
    refreshError.value = ''
  } catch (e: unknown) {
    if (myId !== requestId) return
    detail.value = null
    refreshError.value = formatApiError(e, '加载实时状态失败')
  }
}

async function loadLogs(myId: number) {
  logsLoading.value = true
  logsError.value = ''
  latestLog.value = null
  try {
    const res = await http.get<PushItem[] | { items: PushItem[] }>(
      `/servers/${props.server.id}/logs`,
      { limit: 1 },
    )
    if (myId !== requestId) return
    const items = parseServerSyncLogs(res)
    latestLog.value = items[0] ?? null
  } catch (e: unknown) {
    if (myId !== requestId) return
    logsError.value = formatApiError(e, '加载同步日志失败')
    latestLog.value = null
  } finally {
    if (myId === requestId) logsLoading.value = false
  }
}

async function loadMetrics(myId: number) {
  metricsLoading.value = true
  metricsError.value = ''
  metricPoints.value = []
  offlineSegments.value = []
  try {
    const res = await http.get<ServerMetricsResponse>(
      `/servers/${props.server.id}/metrics`,
      { hours: 24 },
    )
    if (myId !== requestId) return
    metricPoints.value = res.points ?? []
    offlineSegments.value = res.offline_segments ?? []
    metricIntervalMinutes.value = res.interval_minutes ?? 10
  } catch (e: unknown) {
    if (myId !== requestId) return
    metricsError.value = formatApiError(e, '加载历史趋势失败')
  } finally {
    if (myId === requestId) metricsLoading.value = false
  }
}

async function refreshAll() {
  const myId = ++requestId
  refreshing.value = true
  refreshError.value = ''
  try {
    await Promise.all([loadDetail(myId), loadLogs(myId), loadMetrics(myId)])
  } finally {
    if (myId === requestId) refreshing.value = false
  }
}

watch(
  () => props.active,
  (on) => {
    if (on) void refreshAll()
  },
)

watch(
  () => props.server.id,
  () => {
    detail.value = null
    metricPoints.value = []
    offlineSegments.value = []
    latestLog.value = null
    if (props.active) void refreshAll()
  },
)

onBeforeUnmount(() => {
  requestId += 1
})
</script>

<style scoped>
.server-inline-detail {
  background: color-mix(in srgb, rgb(var(--v-theme-surface)) 95%, rgb(var(--v-theme-on-surface)));
  color: rgb(var(--v-theme-on-surface));
}

.server-inline-detail :deep(.v-list-item-title) {
  color: rgb(var(--v-theme-on-surface));
}

.server-inline-detail :deep(.v-list-item-subtitle) {
  color: rgba(var(--v-theme-on-surface), 0.72);
}
</style>
