<!--
  组件名称：TaskList.vue
  组件描述：性能测试任务管理列表（CRUD + 执行/停止操作）

  @author czj
  @date 2026-08-12
-->

<template>
  <div class="task-list-page">
    <div class="toolbar">
      <el-button type="primary" @click="openCreateDialog">
        <el-icon><Plus /></el-icon>新建任务
      </el-button>
      <el-select v-model="statusFilter" placeholder="全部状态" clearable style="width: 140px" @change="loadTasks">
        <el-option label="全部" value="" />
        <el-option label="等待中" value="pending" />
        <el-option label="运行中" value="running" />
        <el-option label="已完成" value="completed" />
        <el-option label="失败" value="failed" />
        <el-option label="已取消" value="cancelled" />
      </el-select>
      <el-button @click="loadTasks"><el-icon><Refresh /></el-icon>刷新</el-button>
    </div>

    <el-card shadow="never">
      <el-table :data="tasks" v-loading="loading" stripe style="width: 100%">
        <el-table-column prop="name" label="任务名称" min-width="160" show-overflow-tooltip />
        <el-table-column prop="targetUrl" label="目标 URL" min-width="200" show-overflow-tooltip />
        <el-table-column prop="method" label="方法" width="80" />
        <el-table-column label="模式" width="90">
          <template #default="{ row }">
            <el-tag size="small">{{ modeLabel(row.mode) }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="并发" width="70" prop="concurrency" />
        <el-table-column label="时长" width="80">
          <template #default="{ row }">{{ row.duration }}s</template>
        </el-table-column>
        <el-table-column label="状态" width="110">
          <template #default="{ row }">
            <el-tag :type="statusType(row.status)" size="small">
              {{ statusLabel(row.status) }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="TPS" width="90">
          <template #default="{ row }">
            {{ row.actualTps != null ? row.actualTps.toFixed(1) : '-' }}
          </template>
        </el-table-column>
        <el-table-column label="错误率" width="90">
          <template #default="{ row }">
            <span :style="{ color: (row.errorRate || 0) > 5 ? '#f56c6c' : '#67c23a' }">
              {{ row.errorRate != null ? (row.errorRate * 100).toFixed(1) + '%' : '-' }}
            </span>
          </template>
        </el-table-column>
        <el-table-column label="创建时间" width="170">
          <template #default="{ row }">{{ formatTime(row.createdAt) }}</template>
        </el-table-column>
        <el-table-column label="操作" width="250" fixed="right">
          <template #default="{ row }">
            <el-button v-if="row.status === 'pending' || row.status === 'completed' || row.status === 'failed' || row.status === 'cancelled'"
              link type="primary" size="small" :loading="runningId === row.id" @click="handleRun(row)">
              执行
            </el-button>
            <el-button v-if="row.status === 'running'" link type="warning" size="small" @click="handleStop(row)">
              停止
            </el-button>
            <el-button v-if="row.status === 'running' || row.status === 'completed'"
              link type="primary" size="small" @click="$emit('viewMonitor', row.id)">
              监控
            </el-button>
            <el-button v-if="row.status === 'completed' || row.status === 'failed'"
              link type="primary" size="small" @click="$emit('viewReport', row.id)">
              报告
            </el-button>
            <el-button link type="primary" size="small" @click="openEditDialog(row)">
              编辑
            </el-button>
            <el-popconfirm title="确定删除此任务？" @confirm="handleDelete(row)">
              <template #reference>
                <el-button link type="danger" size="small">删除</el-button>
              </template>
            </el-popconfirm>
          </template>
        </el-table-column>
      </el-table>

      <div class="pagination">
        <el-pagination
          v-model:current-page="page"
          v-model:page-size="pageSize"
          :total="total"
          :page-sizes="[10, 20, 50]"
          layout="total, sizes, prev, pager, next"
          @change="loadTasks"
        />
      </div>
    </el-card>

    <!-- 创建/编辑任务弹窗 -->
    <el-dialog v-model="dialogVisible" :title="editingTask ? '编辑任务' : '新建任务'" width="680px" top="3vh">
      <el-form ref="formRef" :model="form" label-position="top" :rules="formRules">
        <el-row :gutter="16">
          <el-col :span="16">
            <el-form-item label="任务名称" prop="name">
              <el-input v-model="form.name" placeholder="输入任务名称" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="HTTP 方法" prop="method">
              <el-select v-model="form.method" style="width: 100%">
                <el-option label="GET" value="GET" />
                <el-option label="POST" value="POST" />
                <el-option label="PUT" value="PUT" />
                <el-option label="DELETE" value="DELETE" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>

        <el-form-item label="目标 URL" prop="targetUrl">
          <el-input v-model="form.targetUrl" placeholder="https://192.168.5.44/platform/api/..." />
        </el-form-item>

        <el-row :gutter="16">
          <el-col :span="8">
            <el-form-item label="压测模式" prop="mode">
              <el-select v-model="form.mode" style="width: 100%" @change="onModeChange">
                <el-option label="并发模式" value="concurrent" />
                <el-option label="QPS 模式" value="qps" />
                <el-option label="阶梯模式" value="step" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="并发数" prop="concurrency">
              <el-input-number v-model="form.concurrency" :min="1" :max="1000" style="width: 100%" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="压测时长(秒)" prop="duration">
              <el-input-number v-model="form.duration" :min="5" :max="3600" style="width: 100%" />
            </el-form-item>
          </el-col>
        </el-row>

        <el-row :gutter="16">
          <el-col :span="8">
            <el-form-item v-if="form.mode === 'qps'" label="目标 QPS" prop="qpsTarget">
              <el-input-number v-model="form.qpsTarget" :min="1" :max="100000" style="width: 100%" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="预热时间(秒)" prop="rampUp">
              <el-input-number v-model="form.rampUp" :min="0" :max="300" style="width: 100%" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item v-if="form.mode === 'step'" label="阶梯并发数" prop="stepConcurrency">
              <el-input-number v-model="form.stepConcurrency" :min="1" :max="500" style="width: 100%" />
            </el-form-item>
          </el-col>
        </el-row>

        <el-row :gutter="16">
          <el-col :span="12">
            <el-form-item label="请求头(JSON)" prop="headers">
              <el-input v-model="form.headers" type="textarea" :rows="2" placeholder='{"Content-Type": "application/json"}' />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="请求体(JSON)" prop="body">
              <el-input v-model="form.body" type="textarea" :rows="2" placeholder='{"key": "value"}' />
            </el-form-item>
          </el-col>
        </el-row>

        <el-row :gutter="16">
          <el-col :span="12">
            <el-form-item label="需要登录认证">
              <el-switch v-model="form.authRequired" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item v-if="form.authRequired" label="账号" prop="accountKey">
              <el-select v-model="form.accountKey" style="width: 100%">
                <el-option label="超级管理员" value="superadmin" />
                <el-option label="管理员" value="admin" />
                <el-option label="普通用户" value="user" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>

        <el-form-item label="描述">
          <el-input v-model="form.description" type="textarea" :rows="2" placeholder="任务描述（可选）" />
        </el-form-item>
      </el-form>

      <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" :loading="saving" @click="handleSave">保存</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
/**
 * 性能测试任务管理列表
 *
 * 功能：CRUD 操作、执行/停止任务、跳转到监控/报告
 */

import { ref, onMounted, reactive } from 'vue'
import { ElMessage } from 'element-plus'
import { Plus, Refresh } from '@element-plus/icons-vue'
import { listTasks, createTask, updateTask, deleteTask, runTask, stopTask } from '@/api/performance'
import type { PerformanceTask, PerformanceTaskListItem, PerformanceTaskCreate } from '@/types/performance'

defineEmits<{
  viewMonitor: [taskId: string]
  viewReport: [taskId: string]
}>()

const loading = ref(false)
const tasks = ref<PerformanceTaskListItem[]>([])
const total = ref(0)
const page = ref(1)
const pageSize = ref(20)
const statusFilter = ref('')

const dialogVisible = ref(false)
const editingTask = ref<PerformanceTask | null>(null)
const saving = ref(false)
const runningId = ref('')
const formRef = ref()

interface TaskForm {
  name: string
  description: string | null
  targetUrl: string
  method: string
  headers: string
  body: string
  bodyTemplate: string | null
  mode: 'concurrent' | 'qps' | 'step'
  concurrency: number
  qpsTarget: number | null
  duration: number
  rampUp: number | null
  stepConcurrency: number | null
  stepDuration: number | null
  authRequired: boolean
  accountKey: string | null
  assertions: any[]
}

const defaultForm = (): TaskForm => ({
  name: '',
  description: null,
  targetUrl: '',
  method: 'GET',
  headers: '',
  body: '',
  bodyTemplate: null,
  mode: 'concurrent',
  concurrency: 10,
  qpsTarget: null,
  duration: 60,
  rampUp: null,
  stepConcurrency: null,
  stepDuration: null,
  authRequired: true,
  accountKey: 'admin',
  assertions: [],
})

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

const formRules = {
  name: [{ required: true, message: '请输入任务名称', trigger: 'blur' }],
  targetUrl: [{ required: true, message: '请输入目标 URL', trigger: 'blur' }],
  method: [{ required: true, message: '请选择 HTTP 方法', trigger: 'change' }],
  mode: [{ required: true, message: '请选择压测模式', trigger: 'change' }],
}

/** 加载任务列表 */
async function loadTasks() {
  loading.value = true
  try {
    const params: any = { page: page.value, pageSize: pageSize.value }
    if (statusFilter.value) params.status = statusFilter.value
    const res = await listTasks(params)
    tasks.value = res.items
    total.value = res.total
  } catch (e: any) {
    ElMessage.error('加载任务列表失败: ' + (e.message || ''))
  } finally {
    loading.value = false
  }
}

/** 打开新建弹窗 */
function openCreateDialog() {
  editingTask.value = null
  Object.assign(form, defaultForm())
  dialogVisible.value = true
}

/** 打开编辑弹窗 */
function openEditDialog(task: PerformanceTask) {
  editingTask.value = task
  Object.assign(form, {
    name: task.name,
    description: task.description,
    targetUrl: task.targetUrl,
    method: task.method,
    headers: task.headers ? JSON.stringify(task.headers, null, 2) : '',
    body: task.body || '',
    bodyTemplate: task.bodyTemplate,
    mode: task.mode,
    concurrency: task.concurrency,
    qpsTarget: task.qpsTarget,
    duration: task.duration,
    rampUp: task.rampUp,
    stepConcurrency: task.stepConcurrency,
    stepDuration: task.stepDuration,
    authRequired: task.authRequired,
    accountKey: task.accountKey,
    assertions: task.assertions || [],
  })
  dialogVisible.value = true
}

/** 模式切换 */
function onModeChange(mode: string) {
  if (mode === 'qps' && !form.qpsTarget) form.qpsTarget = 100
  if (mode === 'step') {
    if (!form.stepConcurrency) form.stepConcurrency = 20
    if (!form.stepDuration) form.stepDuration = 30
  }
}

/** 保存任务 */
async function handleSave() {
  if (!formRef.value) return
  try {
    await formRef.value.validate()
  } catch {
    return
  }

  saving.value = true
  try {
    const data: any = {
      name: form.name,
      description: form.description || null,
      targetUrl: form.targetUrl,
      method: form.method,
      headers: form.headers ? JSON.parse(form.headers) : null,
      body: form.body || null,
      bodyTemplate: form.bodyTemplate,
      mode: form.mode,
      concurrency: form.concurrency,
      qpsTarget: form.mode === 'qps' ? form.qpsTarget : null,
      duration: form.duration,
      rampUp: form.rampUp || null,
      stepConcurrency: form.mode === 'step' ? form.stepConcurrency : null,
      stepDuration: form.mode === 'step' ? (form.stepDuration || 30) : null,
      authRequired: form.authRequired,
      accountKey: form.authRequired ? form.accountKey : null,
      assertions: [],
    }

    if (editingTask.value) {
      await updateTask(editingTask.value.id, data)
      ElMessage.success('任务已更新')
    } else {
      await createTask(data as PerformanceTaskCreate)
      ElMessage.success('任务已创建')
    }

    dialogVisible.value = false
    await loadTasks()
  } catch (e: any) {
    ElMessage.error('保存失败: ' + (e.response?.data?.detail || e.message || ''))
  } finally {
    saving.value = false
  }
}

/** 执行任务 */
async function handleRun(task: PerformanceTaskListItem) {
  runningId.value = task.id
  try {
    const res = await runTask(task.id)
    ElMessage.success(res.message || '任务已开始执行')
    await loadTasks()
  } catch (e: any) {
    ElMessage.error('执行失败: ' + (e.response?.data?.detail || e.message || ''))
  } finally {
    runningId.value = ''
  }
}

/** 停止任务 */
async function handleStop(task: PerformanceTaskListItem) {
  try {
    const res = await stopTask(task.id)
    ElMessage.success(res.message || '已发送停止信号')
    await loadTasks()
  } catch (e: any) {
    ElMessage.error('停止失败: ' + (e.response?.data?.detail || e.message || ''))
  }
}

/** 删除任务 */
async function handleDelete(task: PerformanceTaskListItem) {
  try {
    await deleteTask(task.id)
    ElMessage.success('任务已删除')
    await loadTasks()
  } catch (e: any) {
    ElMessage.error('删除失败: ' + (e.response?.data?.detail || e.message || ''))
  }
}

/** 状态标签类型 */
function statusType(status: string) {
  const map: Record<string, string> = { completed: 'success', running: 'primary', pending: 'info', failed: 'danger', cancelled: 'warning' }
  return map[status] || 'info'
}

/** 状态标签文字 */
function statusLabel(status: string) {
  const map: Record<string, string> = { completed: '已完成', running: '运行中', pending: '等待中', failed: '失败', cancelled: '已取消' }
  return map[status] || status
}

/** 模式标签 */
function modeLabel(mode: string) {
  const map: Record<string, string> = { concurrent: '并发', qps: 'QPS', step: '阶梯' }
  return map[mode] || mode
}

/** 格式化时间 */
function formatTime(t: string) {
  return t?.replace('T', ' ').substring(0, 19) || ''
}

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

<style scoped>
.task-list-page {
  padding: 0;
}

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

.pagination {
  display: flex;
  justify-content: flex-end;
  margin-top: 16px;
}
</style>