<!--
  页面名称：ScheduledTasks.vue
  页面描述：安全测试定时任务页面（任务列表 / 创建编辑 / 立即执行 / 运行历史）
  路径：/security/scheduled-tasks

  @author czj
  @date 2026-08-19
-->
<template>
  <div class="security-scheduled-tasks-page">
    <!-- 页面头部 -->
    <div class="page-header">
      <h2>定时任务</h2>
      <div class="header-actions">
        <el-button @click="loadTasks">
          <el-icon><Refresh /></el-icon>
          刷新
        </el-button>
        <el-button type="primary" @click="openCreate">
          <el-icon><Plus /></el-icon>
          新建任务
        </el-button>
      </div>
    </div>

    <el-alert
      title="安全测试定时任务将按周期自动执行所选模块的安全用例，执行完成后自动生成报告到安全测试报告中心；若到点时有执行正在进行将自动跳过本次。"
      type="info"
      :closable="false"
      show-icon
      style="margin-bottom: 16px"
    />

    <!-- 任务列表 -->
    <el-card shadow="never">
      <el-table
        :data="tasks"
        stripe
        style="width: 100%"
        v-loading="loading"
        empty-text="暂无安全测试定时任务"
      >
        <el-table-column prop="name" label="任务名称" min-width="160" />
        <el-table-column label="执行模块" min-width="200">
          <template #default="{ row }">
            <template v-if="row.module_names?.length">
              <el-tag
                v-for="name in row.module_names"
                :key="name"
                size="small"
                type="info"
                style="margin-right: 4px"
              >
                {{ name }}
              </el-tag>
            </template>
            <span v-else style="color: #909399">未选择</span>
          </template>
        </el-table-column>
        <el-table-column prop="config_name" label="测试配置" min-width="140">
          <template #default="{ row }">
            <el-tag size="small" type="warning">{{ row.config_name || '-' }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="schedule_description" label="周期" min-width="140" />
        <el-table-column label="自动报告" width="90" align="center">
          <template #default="{ row }">
            <el-tag :type="row.auto_report ? 'success' : 'info'" size="small">
              {{ row.auto_report ? '开启' : '关闭' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="状态" width="80" align="center">
          <template #default="{ row }">
            <el-switch
              :model-value="row.enabled"
              :disabled="togglingId === row.id"
              @change="(val: boolean) => handleToggle(row, val)"
            />
          </template>
        </el-table-column>
        <el-table-column label="上次执行" width="170">
          <template #default="{ row }">
            {{ formatTime(row.last_run_at) }}
          </template>
        </el-table-column>
        <el-table-column label="下次执行" width="170">
          <template #default="{ row }">
            <span :style="{ color: row.enabled ? '#409eff' : '#909399' }">
              {{ formatTime(row.next_run_at) }}
            </span>
          </template>
        </el-table-column>
        <el-table-column prop="run_count" label="执行次数" width="90" align="center" />
        <el-table-column label="操作" width="230" fixed="right">
          <template #default="{ row }">
            <el-button
              size="small"
              type="primary"
              link
              :loading="runningId === row.id"
              @click="handleRun(row)"
            >
              <el-icon><VideoPlay /></el-icon>
              立即执行
            </el-button>
            <el-button size="small" type="primary" link @click="openRuns(row)">
              <el-icon><List /></el-icon>
              运行记录
            </el-button>
            <el-button size="small" type="primary" link @click="openEdit(row)">
              <el-icon><Edit /></el-icon>
              编辑
            </el-button>
            <el-button size="small" type="danger" link @click="handleDelete(row)">
              <el-icon><Delete /></el-icon>
              删除
            </el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>

    <!-- 创建 / 编辑对话框 -->
    <el-dialog
      v-model="dialogVisible"
      :title="isEdit ? '编辑安全测试定时任务' : '新建安全测试定时任务'"
      width="620px"
      :close-on-click-modal="false"
      destroy-on-close
    >
      <el-form
        ref="formRef"
        :model="form"
        :rules="formRules"
        label-width="100px"
        label-position="right"
      >
        <el-form-item label="任务名称" prop="name">
          <el-input
            v-model="form.name"
            placeholder="如：每日安全扫描"
            maxlength="100"
            clearable
          />
        </el-form-item>

        <el-form-item label="执行模块" prop="module_ids">
          <el-select
            v-model="form.module_ids"
            multiple
            filterable
            collapse-tags
            collapse-tags-tooltip
            style="width: 100%"
            placeholder="选择要执行的安全测试模块"
            :loading="modulesLoading"
          >
            <el-option
              v-for="m in modules"
              :key="m.id"
              :label="`${m.name}（${m.caseCount ?? 0} 用例）`"
              :value="m.id"
            />
          </el-select>
        </el-form-item>

        <el-form-item label="测试配置" prop="config_id">
          <el-select
            v-model="form.config_id"
            style="width: 100%"
            placeholder="选择安全测试配置"
            :loading="configsLoading"
          >
            <el-option
              v-for="c in configs"
              :key="c.id"
              :label="c.name"
              :value="c.id"
            />
          </el-select>
        </el-form-item>

        <el-form-item label="周期模式" prop="schedule_type">
          <el-radio-group v-model="form.schedule_type">
            <el-radio-button value="interval">按间隔</el-radio-button>
            <el-radio-button value="daily">每天定时</el-radio-button>
            <el-radio-button value="weekly">每周定时</el-radio-button>
          </el-radio-group>
        </el-form-item>

        <!-- 按间隔 -->
        <el-form-item v-if="form.schedule_type === 'interval'" label="间隔" prop="interval_value">
          <div style="display: flex; gap: 8px; width: 100%">
            <el-input-number
              v-model="form.interval_value"
              :min="1"
              :max="99999"
              style="width: 160px"
            />
            <el-select v-model="form.interval_unit" style="width: 140px">
              <el-option label="分钟" value="minutes" />
              <el-option label="小时" value="hours" />
              <el-option label="天" value="days" />
            </el-select>
          </div>
        </el-form-item>

        <!-- 每天定时 -->
        <el-form-item v-if="form.schedule_type === 'daily'" label="执行时间" prop="run_time">
          <el-time-select
            v-model="form.run_time"
            start="00:00"
            step="00:30"
            end="23:30"
            placeholder="选择执行时间"
            style="width: 160px"
          />
        </el-form-item>

        <!-- 每周定时 -->
        <el-form-item
          v-if="form.schedule_type === 'weekly'"
          label="执行时间"
          prop="run_time"
        >
          <el-time-select
            v-model="form.run_time"
            start="00:00"
            step="00:30"
            end="23:30"
            placeholder="选择执行时间"
            style="width: 160px"
          />
        </el-form-item>
        <el-form-item
          v-if="form.schedule_type === 'weekly'"
          label="星期"
          prop="weekdays"
        >
          <el-checkbox-group v-model="form.weekdays">
            <el-checkbox-button
              v-for="(label, idx) in WEEKDAY_LABELS"
              :key="idx"
              :value="idx"
            >
              {{ label }}
            </el-checkbox-button>
          </el-checkbox-group>
        </el-form-item>

        <el-form-item label="自动报告">
          <el-switch v-model="form.auto_report" />
          <span class="form-tip">执行完成后自动生成 Markdown 报告到安全报告中心</span>
        </el-form-item>

        <el-form-item label="启用">
          <el-switch v-model="form.enabled" />
          <span class="form-tip">停用后不会按周期触发</span>
        </el-form-item>
      </el-form>

      <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" :loading="saving" @click="handleSave">
          {{ saving ? '保存中...' : '保存' }}
        </el-button>
      </template>
    </el-dialog>

    <!-- 运行历史抽屉 -->
    <el-drawer
      v-model="runsDrawerVisible"
      :title="`运行记录 - ${currentTaskName}`"
      size="60%"
      destroy-on-close
    >
      <el-table :data="runs" v-loading="runsLoading" empty-text="暂无运行记录" stripe>
        <el-table-column prop="name" label="执行名称" min-width="180" />
        <el-table-column label="状态" width="100">
          <template #default="{ row }">
            <el-tag :type="statusTag(row.status)" size="small">
              {{ statusLabel(row.status) }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="漏洞数" width="100">
          <template #default="{ row }">{{ row.vulnerability_count ?? '-' }}</template>
        </el-table-column>
        <el-table-column label="高危/中危/低危" width="180">
          <template #default="{ row }">
            {{ row.high_count ?? 0 }}/{{ row.medium_count ?? 0 }}/{{ row.low_count ?? 0 }}
          </template>
        </el-table-column>
        <el-table-column label="耗时" width="90">
          <template #default="{ row }">{{ row.duration?.toFixed(1) || 0 }}s</template>
        </el-table-column>
        <el-table-column label="执行时间" width="170">
          <template #default="{ row }">{{ formatTime(row.created_at) }}</template>
        </el-table-column>
        <el-table-column label="操作" width="110">
          <template #default>
            <el-button size="small" type="primary" link @click="goReports">
              查看报告
            </el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-drawer>
  </div>
</template>

<script setup lang="ts">
/**
 * 安全测试定时任务页面
 *
 * 功能：
 * 1. 安全测试定时任务列表（状态/周期/配置/上下次执行时间）
 * 2. 创建/编辑任务（选择安全模块 + 选择测试配置 + 周期设置 + 自动报告）
 * 3. 立即执行 / 启停 / 删除
 * 4. 运行历史查看（跳转安全测试报告中心查看报告）
 */

import { reactive, ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Refresh, Plus, VideoPlay, List, Edit, Delete } from '@element-plus/icons-vue'
import { securityScheduledTaskApi, type SecurityScheduledTask } from '@/api/securityScheduledTasks'
import { moduleApi } from '@/api/modules'
import { getSecurityConfigs } from '@/api/security'
import type { SecurityConfig } from '@/types/security'

const router = useRouter()

const WEEKDAY_LABELS = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']

// ==================== 响应式数据 ====================

const tasks = ref<SecurityScheduledTask[]>([])
const loading = ref(false)

const dialogVisible = ref(false)
const isEdit = ref(false)
const saving = ref(false)
const formRef = ref()
const editId = ref('')

const modules = ref<any[]>([])
const modulesLoading = ref(false)

const configs = ref<SecurityConfig[]>([])
const configsLoading = ref(false)

const togglingId = ref('')
const runningId = ref('')

const runsDrawerVisible = ref(false)
const runsLoading = ref(false)
const runs = ref<any[]>([])
const currentTaskName = ref('')

// ==================== 表单 ====================

interface TaskForm {
  name: string
  module_ids: string[]
  config_id: string
  schedule_type: 'interval' | 'daily' | 'weekly'
  interval_value: number
  interval_unit: 'minutes' | 'hours' | 'days'
  run_time: string
  weekdays: number[]
  auto_report: boolean
  enabled: boolean
}

const createEmptyForm = (): TaskForm => ({
  name: '',
  module_ids: [],
  config_id: '',
  schedule_type: 'interval',
  interval_value: 30,
  interval_unit: 'minutes',
  run_time: '',
  weekdays: [1, 2, 3, 4, 5],
  auto_report: true,
  enabled: true,
})

const form = reactive<TaskForm>(createEmptyForm())

const formRules = {
  name: [{ required: true, message: '请输入任务名称', trigger: 'blur' }],
  module_ids: [
    {
      validator: (_rule: any, value: string[], callback: (e?: Error) => void) => {
        if (!value || value.length === 0) {
          callback(new Error('请至少选择一个执行模块'))
        } else {
          callback()
        }
      },
      trigger: 'change',
    },
  ],
  config_id: [{ required: true, message: '请选择安全测试配置', trigger: 'change' }],
  schedule_type: [{ required: true, message: '请选择周期模式', trigger: 'change' }],
  interval_value: [
    {
      validator: (_rule: any, value: number, callback: (e?: Error) => void) => {
        if (form.schedule_type === 'interval' && (!value || value <= 0)) {
          callback(new Error('请输入有效的间隔值'))
        } else {
          callback()
        }
      },
      trigger: 'blur',
    },
  ],
  run_time: [
    {
      validator: (_rule: any, value: string, callback: (e?: Error) => void) => {
        if (form.schedule_type !== 'interval' && !value) {
          callback(new Error('请选择执行时间'))
        } else {
          callback()
        }
      },
      trigger: 'change',
    },
  ],
  weekdays: [
    {
      validator: (_rule: any, value: number[], callback: (e?: Error) => void) => {
        if (form.schedule_type === 'weekly' && (!value || value.length === 0)) {
          callback(new Error('请至少选择一个星期'))
        } else {
          callback()
        }
      },
      trigger: 'change',
    },
  ],
}

// ==================== 方法 ====================

const formatTime = (time: string | null) => {
  if (!time) return '-'
  return new Date(time).toLocaleString('zh-CN', {
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
  })
}

const statusLabel = (status: string) => {
  const map: Record<string, string> = {
    pending: '待执行',
    running: '执行中',
    completed: '已完成',
    cancelled: '已取消',
    failed: '失败',
  }
  return map[status] || status
}

const statusTag = (status: string) => {
  const map: Record<string, string> = {
    pending: 'info',
    running: 'warning',
    completed: 'success',
    cancelled: 'info',
    failed: 'danger',
  }
  return map[status] || 'info'
}

const loadTasks = async () => {
  loading.value = true
  try {
    const res = await securityScheduledTaskApi.list()
    tasks.value = res.items
  } catch (err: any) {
    ElMessage.error('加载安全测试定时任务失败：' + (err?.message || '未知错误'))
  } finally {
    loading.value = false
  }
}

const loadModules = async () => {
  modulesLoading.value = true
  try {
    const res = await moduleApi.list(0, 200, undefined, 'security')
    modules.value = res.items
  } catch (err: any) {
    ElMessage.error('加载安全测试模块列表失败：' + (err?.message || '未知错误'))
  } finally {
    modulesLoading.value = false
  }
}

const loadConfigs = async () => {
  configsLoading.value = true
  try {
    const res = await getSecurityConfigs(0, 100)
    const data = (res as any).data || res
    configs.value = data.items || []
  } catch (err: any) {
    ElMessage.error('加载安全测试配置失败：' + (err?.message || '未知错误'))
  } finally {
    configsLoading.value = false
  }
}

const openCreate = async () => {
  isEdit.value = false
  editId.value = ''
  Object.assign(form, createEmptyForm())
  if (modules.value.length === 0) await loadModules()
  if (configs.value.length === 0) await loadConfigs()
  dialogVisible.value = true
  formRef.value?.clearValidate()
}

const openEdit = async (task: SecurityScheduledTask) => {
  isEdit.value = true
  editId.value = task.id
  Object.assign(form, {
    name: task.name,
    module_ids: [...(task.module_ids || [])],
    config_id: task.config_id || '',
    schedule_type: task.schedule_type,
    interval_value: task.interval_value,
    interval_unit: task.interval_unit,
    run_time: task.run_time || '',
    weekdays: [...(task.weekdays || [])],
    auto_report: task.auto_report,
    enabled: task.enabled,
  })
  if (modules.value.length === 0) await loadModules()
  if (configs.value.length === 0) await loadConfigs()
  dialogVisible.value = true
  formRef.value?.clearValidate()
}

const handleSave = async () => {
  const valid = await formRef.value?.validate().catch(() => false)
  if (!valid) return

  saving.value = true
  try {
    const payload = {
      name: form.name.trim(),
      module_ids: form.module_ids,
      config_id: form.config_id,
      schedule_type: form.schedule_type,
      interval_value: form.interval_value,
      interval_unit: form.interval_unit,
      run_time: form.schedule_type === 'interval' ? '' : form.run_time,
      weekdays: form.schedule_type === 'weekly' ? form.weekdays : [],
      auto_report: form.auto_report,
      enabled: form.enabled,
    }
    if (isEdit.value) {
      await securityScheduledTaskApi.update(editId.value, payload)
      ElMessage.success('安全测试定时任务已更新')
    } else {
      await securityScheduledTaskApi.create(payload)
      ElMessage.success('安全测试定时任务已创建')
    }
    dialogVisible.value = false
    await loadTasks()
  } catch (err: any) {
    ElMessage.error('保存安全测试定时任务失败：' + (err?.message || '未知错误'))
  } finally {
    saving.value = false
  }
}

const handleToggle = async (task: SecurityScheduledTask, enabled: boolean) => {
  togglingId.value = task.id
  try {
    await securityScheduledTaskApi.toggle(task.id, enabled)
    ElMessage.success(enabled ? '任务已启用' : '任务已停用')
    await loadTasks()
  } catch (err: any) {
    ElMessage.error('切换任务状态失败：' + (err?.message || '未知错误'))
  } finally {
    togglingId.value = ''
  }
}

const handleRun = async (task: SecurityScheduledTask) => {
  try {
    await ElMessageBox.confirm(
      `确定立即执行安全测试任务「${task.name}」吗？将执行其选中的所有模块安全用例。`,
      '立即执行',
      { type: 'warning', confirmButtonText: '执行', cancelButtonText: '取消' }
    )
  } catch {
    return
  }

  runningId.value = task.id
  try {
    const res = await securityScheduledTaskApi.run(task.id)
    ElMessage.success(res.message || '任务已触发执行')
    // 延迟刷新，等待执行状态写入
    setTimeout(loadTasks, 3000)
  } catch (err: any) {
    ElMessage.error('触发执行失败：' + (err?.message || '未知错误'))
  } finally {
    runningId.value = ''
  }
}

const handleDelete = async (task: SecurityScheduledTask) => {
  try {
    await ElMessageBox.confirm(
      `确定删除安全测试定时任务「${task.name}」吗？已产生的执行记录与报告不受影响。`,
      '删除定时任务',
      { type: 'warning', confirmButtonText: '删除', cancelButtonText: '取消' }
    )
  } catch {
    return
  }

  try {
    await securityScheduledTaskApi.remove(task.id)
    ElMessage.success('安全测试定时任务已删除')
    await loadTasks()
  } catch (err: any) {
    ElMessage.error('删除安全测试定时任务失败：' + (err?.message || '未知错误'))
  }
}

const openRuns = async (task: SecurityScheduledTask) => {
  currentTaskName.value = task.name
  runs.value = []
  runsDrawerVisible.value = true
  runsLoading.value = true
  try {
    const res = await securityScheduledTaskApi.getRuns(task.id, { skip: 0, limit: 50 })
    runs.value = res.items
  } catch (err: any) {
    ElMessage.error('加载运行记录失败：' + (err?.message || '未知错误'))
  } finally {
    runsLoading.value = false
  }
}

const goReports = () => {
  runsDrawerVisible.value = false
  router.push('/reports/security')
}

// ==================== 生命周期 ====================

onMounted(() => {
  loadTasks()
})
</script>

<style lang="scss" scoped>
.security-scheduled-tasks-page {
  .page-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px;

    h2 {
      margin: 0;
      font-size: 20px;
    }

    .header-actions {
      display: flex;
      gap: 8px;
    }
  }

  .form-tip {
    margin-left: 8px;
    font-size: 12px;
    color: #909399;
  }
}
</style>