<script setup lang="ts">
import { ref, computed } from 'vue'
import type { WatchSlot } from '@/composables/useWatchPins'
import {
  WATCH_TTL_OPTIONS,
  normalizeWatchTtlMinutes,
  watchTtlLabel,
  watchTtlShortLabel,
  type WatchTtlMinutes,
} from '@/constants/watchTtl'
import { formatBytesPerSec, formatRemaining, probeStatusColor, probeStatusLabel, formatProbeError, isPsutilMissingError, isWatchMetricsPending, loadAvgColor, formatLoadAvg } from '@/utils/watchFormat'
import WatchSparkline from '@/components/watch/WatchSparkline.vue'
import WatchMetricBar from '@/components/watch/WatchMetricBar.vue'

const props = defineProps<{
  slot: WatchSlot
  psutilInstallLoading?: boolean
}>()

const emit = defineEmits<{
  remove: [slotIndex: number]
  processes: [slot: WatchSlot]
  history: [slot: WatchSlot]
  pick: [slotIndex: number]
  monitoring: [slotIndex: number, enabled: boolean]
  ttl: [slotIndex: number, minutes: WatchTtlMinutes]
  installPsutil: [slotIndex: number]
}>()

const monitoringOn = computed(() => props.slot.monitoring_enabled !== false)
const slotTtlMinutes = computed(() =>
  normalizeWatchTtlMinutes(props.slot.ttl_minutes ?? (props.slot.ttl_hours === 24 ? 1440 : props.slot.ttl_hours === 8 ? 480 : undefined)),
)
const showPsutilInstall = computed(() =>
  monitoringOn.value && isPsutilMissingError(props.slot.metrics?.error, props.slot.metrics?.probe_status),
)

const chartMetric = ref<'cpu_pct' | 'mem_pct' | 'disk_pct'>('cpu_pct')

const load1 = computed(() => props.slot.metrics?.load_1)
const metricsPending = computed(() => monitoringOn.value && isWatchMetricsPending(props.slot.metrics))
</script>

<template>
  <v-card
    v-if="!slot.empty"
    elevation="0"
    border
    rounded="lg"
    :link="false"
    :ripple="false"
    class="watch-slot-card pa-3 watch-slot-card--filled"
    :class="{
      'watch-slot-card--error': monitoringOn && slot.metrics?.probe_status && slot.metrics.probe_status !== 'ok',
      'watch-slot-card--paused': !monitoringOn,
    }"
    role="button"
    tabindex="0"
    @click="emit('history', slot)"
    @keydown.enter.prevent="emit('history', slot)"
  >
    <div class="d-flex align-center mb-2" @click.stop>
      <div class="text-subtitle-2 text-truncate flex-grow-1" :title="slot.server_name">
        {{ slot.server_name || `ID ${slot.server_id}` }}
      </div>
      <v-chip size="x-small" variant="tonal" color="info" label>
        槽 {{ slot.slot_index + 1 }}
      </v-chip>
      <v-switch
        :model-value="monitoringOn"
        density="compact"
        hide-details
        color="primary"
        class="watch-slot-switch ml-1"
        @click.stop
        @update:model-value="emit('monitoring', slot.slot_index, $event ?? false)"
      />
      <v-btn icon="mdi-close" size="x-small" variant="text" @click="emit('remove', slot.slot_index)" />
    </div>

    <div class="watch-ttl-row mb-2" @click.stop>
      <span class="text-caption text-medium-emphasis watch-ttl-label">时长</span>
      <div class="watch-ttl-chips d-flex flex-wrap ga-1">
        <v-chip
          v-for="opt in WATCH_TTL_OPTIONS"
          :key="opt.minutes"
          :color="slotTtlMinutes === opt.minutes ? 'primary' : undefined"
          :variant="slotTtlMinutes === opt.minutes ? 'flat' : 'outlined'"
          size="x-small"
          label
          class="watch-ttl-chip"
          @click="emit('ttl', slot.slot_index, opt.minutes)"
        >
          {{ opt.label }}
        </v-chip>
      </div>
    </div>

    <div v-if="!monitoringOn" class="text-caption text-medium-emphasis mb-2" @click.stop>
      实时监测已关闭 · 槽位保留 · Agent 恢复 60s 智能上报
    </div>

    <template v-if="monitoringOn">
    <div @click.stop>
    <div
      v-if="metricsPending"
      class="watch-slot-waiting d-flex flex-column align-center justify-center text-center py-6"
    >
      <v-progress-circular indeterminate color="primary" size="36" width="3" />
      <div class="text-body-2 mt-3">等待服务器回传信息…</div>
      <div class="text-caption text-medium-emphasis mt-1 px-2">
        探针约每 5 秒轮询，首次通常 5–15 秒
      </div>
    </div>

    <template v-else>
    <v-chip
      v-if="slot.metrics?.probe_status"
      size="x-small"
      :color="probeStatusColor(slot.metrics.probe_status)"
      variant="tonal"
      class="mb-2"
      label
    >
      {{ probeStatusLabel(slot.metrics.probe_status) }}
    </v-chip>

    <WatchMetricBar label="CPU" :value="slot.metrics?.cpu_pct" />
    <WatchMetricBar label="内存" :value="slot.metrics?.mem_pct" />
    <WatchMetricBar label="硬盘" :value="slot.metrics?.disk_pct" />

    <div class="d-flex align-center justify-space-between text-caption mb-2 mt-1">
      <span class="text-medium-emphasis">负载</span>
      <v-tooltip location="top" text="1 分钟平均负载，与宝塔面板「负载」相同（非 CPU 百分比）">
        <template #activator="{ props: tipProps }">
          <v-chip
            v-bind="tipProps"
            size="x-small"
            :color="loadAvgColor(load1)"
            variant="tonal"
            label
          >
            {{ formatLoadAvg(load1) }}
          </v-chip>
        </template>
      </v-tooltip>
    </div>

    <div class="text-caption text-medium-emphasis mb-1">
      ↑ {{ formatBytesPerSec(slot.metrics?.net_up_bps) }}
      · ↓ {{ formatBytesPerSec(slot.metrics?.net_down_bps) }}
    </div>
    <div class="text-caption text-medium-emphasis mb-2">
      读 {{ formatBytesPerSec(slot.metrics?.disk_read_bps) }}
      · 写 {{ formatBytesPerSec(slot.metrics?.disk_write_bps) }}
    </div>

    <v-btn-toggle v-model="chartMetric" density="compact" variant="outlined" divided class="mb-1">
      <v-btn value="cpu_pct" size="x-small">CPU</v-btn>
      <v-btn value="mem_pct" size="x-small">内存</v-btn>
      <v-btn value="disk_pct" size="x-small">硬盘</v-btn>
    </v-btn-toggle>

    <WatchSparkline :points="slot.sparkline || []" :metric="chartMetric" />

    <div
      v-if="slot.metrics?.error"
      class="text-caption text-error mt-1"
      :title="formatProbeError(slot.metrics.error, slot.metrics.probe_status)"
    >
      <div class="text-truncate">
        {{ formatProbeError(slot.metrics.error, slot.metrics.probe_status) }}
      </div>
      <v-btn
        v-if="showPsutilInstall"
        size="x-small"
        variant="tonal"
        color="primary"
        class="mt-1"
        :loading="props.psutilInstallLoading"
        @click.stop="emit('installPsutil', slot.slot_index)"
      >
        安装 psutil（SSH）
      </v-btn>
    </div>

    <div class="d-flex align-center justify-space-between mt-2">
      <span class="text-caption text-medium-emphasis">
        剩余 {{ formatRemaining(slot.remaining_sec) }} · {{ watchTtlShortLabel(slotTtlMinutes) }}
      </span>
      <div class="d-flex ga-1">
        <v-btn size="x-small" variant="text" @click.stop="emit('processes', slot)">进程</v-btn>
        <v-btn size="x-small" variant="text" @click.stop="emit('history', slot)">历史</v-btn>
      </div>
    </div>
    </template>

    <div v-if="metricsPending" class="d-flex align-center justify-space-between mt-2">
      <span class="text-caption text-medium-emphasis">
        剩余 {{ formatRemaining(slot.remaining_sec) }} · {{ watchTtlShortLabel(slotTtlMinutes) }}
      </span>
      <v-btn size="x-small" variant="text" @click.stop="emit('history', slot)">历史</v-btn>
    </div>
    </div>
    </template>

    <div v-else class="d-flex align-center justify-space-between mt-2" @click.stop>
      <span class="text-caption text-medium-emphasis">已暂停 · {{ watchTtlLabel(slotTtlMinutes) }}</span>
      <div class="d-flex ga-1">
        <v-btn size="x-small" variant="text" @click.stop="emit('history', slot)">历史</v-btn>
      </div>
    </div>
  </v-card>

  <v-card
    v-else
    elevation="0"
    border
    rounded="lg"
    :link="false"
    :ripple="false"
    class="watch-slot-card watch-slot-card--empty d-flex align-center justify-center pa-4"
    variant="outlined"
    role="button"
    tabindex="0"
    @click="emit('pick', slot.slot_index)"
    @keydown.enter.prevent="emit('pick', slot.slot_index)"
  >
    <div class="text-center text-medium-emphasis">
      <v-icon size="28" class="mb-1">mdi-plus-circle-outline</v-icon>
      <div class="text-caption">槽 {{ slot.slot_index + 1 }} · 添加监测</div>
    </div>
  </v-card>
</template>

<style scoped>
.watch-slot-card {
  min-height: 280px;
}
/* Vuetify v-card--link 会在 hover 时铺 v-card__overlay 灰层，此处仅保留外框高亮 */
.watch-slot-card :deep(.v-card__overlay) {
  opacity: 0 !important;
}
.watch-slot-card--empty {
  min-height: 220px;
  border-style: dashed !important;
  cursor: pointer;
  transition: border-color 0.15s ease;
}
.watch-slot-card--empty:hover {
  border-color: rgb(var(--v-theme-primary)) !important;
}
.watch-slot-card--filled {
  cursor: pointer;
  transition: border-color 0.15s ease;
}
.watch-slot-card--filled:hover {
  border-color: rgb(var(--v-theme-primary)) !important;
}
.watch-slot-card--error {
  border-color: rgb(var(--v-theme-error)) !important;
}
.watch-slot-card--paused {
  opacity: 0.72;
  background: rgba(var(--v-theme-surface-variant), 0.15);
}
.watch-slot-switch {
  flex: 0 0 auto;
  transform: scale(0.85);
}
.watch-ttl-row {
  display: flex;
  align-items: flex-start;
  gap: 6px;
}
.watch-ttl-label {
  flex: 0 0 auto;
  line-height: 24px;
}
.watch-ttl-chips {
  flex: 1 1 auto;
  min-width: 0;
}
.watch-ttl-chip {
  cursor: pointer;
  user-select: none;
}
.watch-slot-waiting {
  min-height: 160px;
}
</style>
