<script setup lang="ts">
import type { AdminScheduledJobRuntimeState } from '@/types/admin'
import type { EditableScheduledJob } from '../../composables/types'
import { formatAdminDateTime } from '@/utils/admin-time'

const timeUnitOptions = [
  { label: '秒', value: 1 },
  { label: '分钟', value: 60 },
  { label: '小时', value: 3600 },
]

function formatJobType(type: string) {
  if (type === 'cloudtentacles_health') return 'cloudtentacles 健康检查'
  return type || '-'
}

function resolveTimeValue(seconds: number) {
  const normalized = Math.max(0, Number(seconds || 0))
  if (normalized >= 3600 && normalized % 3600 === 0) {
    return { amount: normalized / 3600, unit: 3600 }
  }
  if (normalized >= 60 && normalized % 60 === 0) {
    return { amount: normalized / 60, unit: 60 }
  }
  return { amount: normalized || 1, unit: 1 }
}

function formatDuration(seconds: number) {
  const value = resolveTimeValue(seconds)
  const unit = timeUnitOptions.find((item) => item.value === value.unit)?.label || '秒'
  return `${value.amount} ${unit}`
}

function bindDuration(job: EditableScheduledJob, key: 'intervalSeconds' | 'cooldownSeconds') {
  const amountKey = `${key}Amount` as keyof EditableScheduledJob
  const unitKey = `${key}Unit` as keyof EditableScheduledJob

  if (!Number(job[amountKey])) {
    const resolved = resolveTimeValue(Number(job[key] || 0))
    ;(job[amountKey] as number) = resolved.amount
    ;(job[unitKey] as number) = resolved.unit
  }

  return computed<number>({
    get: () => Number(job[amountKey] || 1),
    set: (value: number) => {
      ;(job[amountKey] as number) = Math.max(1, Number(value || 1))
      job[key] = Number(job[amountKey] || 1) * Number(job[unitKey] || 1)
    },
  })
}

function bindDurationUnit(job: EditableScheduledJob, key: 'intervalSeconds' | 'cooldownSeconds') {
  const amountKey = `${key}Amount` as keyof EditableScheduledJob
  const unitKey = `${key}Unit` as keyof EditableScheduledJob

  if (!Number(job[unitKey])) {
    const resolved = resolveTimeValue(Number(job[key] || 0))
    ;(job[amountKey] as number) = resolved.amount
    ;(job[unitKey] as number) = resolved.unit
  }

  return computed<number>({
    get: () => Number(job[unitKey] || 1),
    set: (value: number) => {
      ;(job[unitKey] as number) = Math.max(1, Number(value || 1))
      job[key] = Number(job[amountKey] || 1) * Number(job[unitKey] || 1)
    },
  })
}

import { computed } from 'vue'

type Props = {
  scheduledJobsForm: {
    enabled: boolean
  }
  scheduledJobs: EditableScheduledJob[]
  scheduledJobRuntime: AdminScheduledJobRuntimeState[]
  scheduledJobsSaving: boolean
  scheduledJobRunningId: string
  handleScheduledJobsSaveConfig: () => void | Promise<void>
  handleScheduledJobRunNow: (jobId: string) => void | Promise<void>
  getScheduledJobRuntime: (jobId: string) => AdminScheduledJobRuntimeState | null
}

defineProps<Props>()
</script>

<template>
  <el-card class="section-card">
    <template #header>
      <div class="card-header">
        <div>
          <span class="card-title">监控任务</span>
          <p class="card-desc">
            间隔表示多久检查一次；冷却表示同一个异常在这段时间内最多通知一次。
          </p>
        </div>
        <div class="card-actions">
          <el-button
            :loading="scheduledJobsSaving"
            type="primary"
            @click="handleScheduledJobsSaveConfig"
            >保存任务</el-button
          >
        </div>
      </div>
    </template>

    <el-form label-width="auto" label-position="top">
      <el-form-item>
        <el-switch v-model="scheduledJobsForm.enabled" active-text="启用监控任务系统" />
      </el-form-item>
    </el-form>

    <el-table :data="scheduledJobs" stripe size="small" style="margin-top: 8px">
      <el-table-column label="任务" min-width="200">
        <template #default="{ row: job }">
          <div>
            <div class="fw-600">{{ formatJobType(job.type) }}</div>
            <el-switch
              v-model="job.enabled"
              size="small"
              active-text="启用"
              style="margin-top: 4px"
            />
          </div>
        </template>
      </el-table-column>
      <el-table-column label="参数" min-width="320">
        <template #default="{ row: job }">
          <div class="job-params">
            <div class="param-row">
              <span class="param-label">检查间隔</span>
              <input
                v-model.number="bindDuration(job, 'intervalSeconds').value"
                type="number"
                min="1"
                class="mini-input"
              />
              <select
                v-model.number="bindDurationUnit(job, 'intervalSeconds').value"
                class="mini-select"
              >
                <option v-for="unit in timeUnitOptions" :key="unit.value" :value="unit.value">
                  {{ unit.label }}
                </option>
              </select>
              <span class="param-hint"
                >每 {{ formatDuration(job.intervalSeconds) }} 检查一次</span
              >
            </div>
            <div class="param-row">
              <span class="param-label">通知冷却</span>
              <input
                v-model.number="bindDuration(job, 'cooldownSeconds').value"
                type="number"
                min="1"
                class="mini-input"
              />
              <select
                v-model.number="bindDurationUnit(job, 'cooldownSeconds').value"
                class="mini-select"
              >
                <option v-for="unit in timeUnitOptions" :key="unit.value" :value="unit.value">
                  {{ unit.label }}
                </option>
              </select>
              <span class="param-hint"
                >同类异常 {{ formatDuration(job.cooldownSeconds) }} 内只通知一次</span
              >
            </div>
            <div class="param-row">
              <span class="param-label">余额阈值</span>
              <input
                v-model.number="job.assetThreshold"
                type="number"
                min="0"
                class="mini-input"
              />
              <span class="param-hint">低于该值时通知</span>
            </div>
          </div>
        </template>
      </el-table-column>
      <el-table-column label="最近状态" min-width="160">
        <template #default="{ row: job }">
          <div class="runtime-info">
            <el-tag
              :type="
                getScheduledJobRuntime(job.id)?.lastStatus === 'success' ? 'success' : 'info'
              "
              size="small"
            >
              {{ getScheduledJobRuntime(job.id)?.lastStatus || 'pending' }}
            </el-tag>
            <span class="param-hint">{{
              getScheduledJobRuntime(job.id)?.lastMessage || '-'
            }}</span>
            <span class="param-hint"
              >余额：{{ getScheduledJobRuntime(job.id)?.lastAsset ?? '-' }}</span
            >
            <span class="param-hint"
              >上次：{{
                formatAdminDateTime(getScheduledJobRuntime(job.id)?.lastRunAt || '')
              }}</span
            >
            <span class="param-hint"
              >下次：{{
                formatAdminDateTime(getScheduledJobRuntime(job.id)?.nextRunAt || '')
              }}</span
            >
          </div>
        </template>
      </el-table-column>
      <el-table-column label="操作" width="110" align="center">
        <template #default="{ row: job }">
          <el-button
            :loading="scheduledJobRunningId === job.id"
            size="small"
            @click="handleScheduledJobRunNow(job.id)"
          >
            立即检查
          </el-button>
        </template>
      </el-table-column>
      <template #empty>
        <el-empty description="暂无可配置的监控任务。" :image-size="60" />
      </template>
    </el-table>
  </el-card>
</template>

<style scoped>
.section-card {
  border-radius: var(--radius-lg);
}

.card-title {
  font-size: var(--text-lg);
  font-weight: 600;
  color: var(--text-primary);
}

.card-desc {
  margin: var(--space-1) 0 0;
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: var(--space-3);
}

.card-actions {
  display: flex;
  gap: var(--space-2);
  flex-shrink: 0;
  flex-wrap: wrap;
}

.job-params {
  display: grid;
  gap: var(--space-2);
}

.param-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.param-label {
  font-size: var(--text-xs);
  color: var(--text-secondary);
  font-weight: 600;
  min-width: 56px;
}

.mini-input {
  width: 100px;
  height: 32px;
  padding: 0 8px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-default);
  background: var(--bg-surface);
  font-size: var(--text-sm);
  text-align: center;
}

.mini-select {
  width: 80px;
  height: 32px;
  padding: 0 4px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-default);
  background: var(--bg-surface);
  font-size: var(--text-sm);
}

.param-hint {
  font-size: var(--text-xs);
  color: var(--text-muted);
}

.runtime-info {
  display: grid;
  gap: 2px;
  font-size: var(--text-xs);
}
</style>
