<!--
  组件名称：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="router.push('/performance/monitor?taskId=' + row.id)">
              监控
            </el-button>
            <el-button v-if="row.status === 'completed' || row.status === 'failed'"
              link type="primary" size="small" @click="router.push('/performance/report?taskId=' + 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="接口预设">
              <el-select
                v-model="form.presetId"
                placeholder="选择预设…"
                clearable
                style="width: 100%"
                @change="onPresetChange"
              >
                <el-option label="无预设（手动填写）" value="" />
                <el-option v-for="p in presets" :key="p.id" :label="p.name" :value="p.id" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>

        <!-- 预设摘要卡片 -->
        <el-card v-if="selectedPreset" shadow="never" class="preset-summary">
          <template #header>
            <div class="preset-summary-header">
              <span class="preset-summary-title">{{ selectedPreset.name }}</span>
              <el-tag size="small" :type="methodTagType(selectedPreset.method)">{{ selectedPreset.method }}</el-tag>
            </div>
          </template>
          <div class="preset-summary-body">
            <div><strong>目标 URL：</strong><code>{{ selectedPreset.targetUrl }}</code></div>
            <div v-if="selectedPreset.description"><strong>描述：</strong>{{ selectedPreset.description }}</div>
            <div>
              <strong>认证：</strong>
              {{ selectedPreset.authRequired ? '需要登录' : '无需登录' }}<template v-if="selectedPreset.authRequired">（{{ accountKeyLabel(selectedPreset.accountKey) }}）</template>
               · 签名：{{ selectedPreset.signRequest ? '需要' : '不需要' }}
            </div>
            <el-button link type="primary" size="small" class="preset-summary-clear" @click="onPresetChange('')">
              清除预设改为手动
            </el-button>
          </div>
        </el-card>

        <el-row :gutter="16">
          <el-col :span="8">
            <el-form-item label="HTTP 方法" prop="method">
              <el-select v-model="form.method" style="width: 100%" :disabled="!!form.presetId">
                <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-col :span="16">
            <el-form-item label="目标 URL" prop="targetUrl">
              <el-input v-model="form.targetUrl" placeholder="https://192.168.5.44/platform/api/..." :disabled="!!form.presetId" />
            </el-form-item>
          </el-col>
        </el-row>

        <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"}' :disabled="!!form.presetId" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item v-if="!form.presetId" label="请求体(JSON)" prop="body">
              <el-input v-model="form.body" type="textarea" :rows="2" placeholder='{"key": "value"}' />
            </el-form-item>
            <el-form-item v-else label="请求体(预设模板)">
              <div class="preset-body-view">
                <pre>{{ presetBodyView }}</pre>
              </div>
            </el-form-item>
          </el-col>
        </el-row>

        <el-row :gutter="16">
          <el-col :span="8">
            <el-form-item label="需要登录认证">
              <el-switch v-model="form.authRequired" :disabled="!!form.presetId" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="请求需要签名">
              <el-switch v-model="form.signRequest" :disabled="!!form.presetId" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item v-if="form.authRequired" label="账号" prop="accountKey">
              <el-select v-model="form.accountKey" style="width: 100%" :disabled="!!form.presetId">
                <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, computed } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { Plus, Refresh } from '@element-plus/icons-vue'
import { listTasks, getTask, createTask, updateTask, deleteTask, runTask, stopTask, listPresets, getPreset } from '@/api/performance'
import type { PerformanceTask, PerformanceTaskListItem, PerformanceTaskCreate, ApiPresetListItem, ApiPreset } from '@/types/performance'

const router = useRouter()

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()

// 预设相关
const presets = ref<ApiPresetListItem[]>([])
const selectedPreset = ref<ApiPreset | null>(null)

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
  signRequest: boolean
  assertions: any[]
  presetId: string
}

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',
  signRequest: false,
  assertions: [],
  presetId: '',
})

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

/** 预设请求体只读展示 */
const presetBodyView = computed(() => {
  const p = selectedPreset.value
  if (!p) return ''
  if (p.bodyTemplate) {
    return JSON.stringify(p.bodyTemplate, null, 2)
  }
  return p.body != null ? JSON.stringify(p.body, null, 2) : ''
})

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
  }
}

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

/** 打开编辑弹窗 */
async function openEditDialog(task: PerformanceTaskListItem) {
  // 表格行是 PerformanceTaskListItem（缺少 body/headers/stepConcurrency 等字段），
  // 必须调用 getTask 获取完整详情再填充表单
  let fullTask: PerformanceTask
  try {
    fullTask = await getTask(task.id)
  } catch {
    // 回退到行数据（至少能显示名称/URL/模式等基本信息）
    fullTask = task as unknown as PerformanceTask
  }
  editingTask.value = fullTask

  // 加载预设列表
  await loadPresets()

  // 如果任务有 presetId，找到对应的预设并回填
  const presetId = fullTask.presetId || ''
  if (presetId) {
    const found = presets.value.find(p => p.id === presetId)
    if (found) {
      // 获取完整预设数据
      try {
        const preset = await getPreset(presetId)
        selectedPreset.value = preset
      } catch {
        selectedPreset.value = null
      }
    } else {
      // 预设已被删除：清除关联，字段保持可编辑
      selectedPreset.value = null
    }
  } else {
    selectedPreset.value = null
  }

  Object.assign(form, {
    name: fullTask.name,
    description: fullTask.description,
    targetUrl: fullTask.targetUrl,
    method: fullTask.method,
    headers: fullTask.headers ? JSON.stringify(fullTask.headers, null, 2) : '',
    body: fullTask.body ? (typeof fullTask.body === 'string' ? fullTask.body : JSON.stringify(fullTask.body, null, 2)) : '',
    bodyTemplate: fullTask.bodyTemplate,
    mode: fullTask.mode,
    concurrency: fullTask.concurrency,
    qpsTarget: fullTask.qpsTarget,
    duration: fullTask.duration,
    rampUp: fullTask.rampUp,
    stepConcurrency: Array.isArray(fullTask.stepConcurrency) ? Math.max(...fullTask.stepConcurrency) : fullTask.stepConcurrency,
    stepDuration: fullTask.stepDuration,
    authRequired: fullTask.authRequired,
    accountKey: fullTask.accountKey,
    signRequest: fullTask.signRequest,
    assertions: fullTask.assertions || [],
    presetId: presetId && selectedPreset.value ? presetId : '',
  })
  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 loadPresets() {
  try {
    const res = await listPresets({ pageSize: 200 })
    presets.value = res.items || []
  } catch {
    presets.value = []
  }
}

/** 预设切换：填充接口字段或清空恢复到手动 */
async function onPresetChange(presetId: string) {
  if (!presetId) {
    // 清空预设，恢复到手动填写
    selectedPreset.value = null
    form.method = 'GET'
    form.targetUrl = ''
    form.headers = ''
    form.body = ''
    form.bodyTemplate = null
    form.authRequired = true
    form.signRequest = false
    form.accountKey = 'admin'
    form.presetId = ''
    return
  }

  // 获取完整预设数据
  try {
    const preset = await getPreset(presetId) as ApiPreset
    selectedPreset.value = preset

    // 填充接口字段
    form.method = preset.method
    form.targetUrl = preset.targetUrl
    form.headers = preset.headers ? JSON.stringify(preset.headers, null, 2) : ''
    if (preset.bodyTemplate) {
      form.body = ''
      form.bodyTemplate = JSON.stringify(preset.bodyTemplate, null, 2)
    } else {
      form.bodyTemplate = null
      form.body = preset.body != null ? JSON.stringify(preset.body, null, 2) : ''
    }
    form.authRequired = preset.authRequired
    form.signRequest = preset.signRequest
    form.accountKey = preset.accountKey || 'superadmin'
    form.presetId = preset.id
  } catch (e: any) {
    ElMessage.error('获取预设详情失败: ' + (e.message || ''))
    selectedPreset.value = null
    form.presetId = ''
  }
}

/** 账号标签 */
function accountKeyLabel(key: string) {
  const map: Record<string, string> = { superadmin: '超级管理员', admin: '管理员', user: '普通用户' }
  return map[key] || key
}

/** 方法标签颜色 */
function methodTagType(method: string) {
  const map: Record<string, string> = { GET: 'success', POST: 'primary', PUT: 'warning', DELETE: 'danger' }
  return map[method] || 'info'
}

/** 保存任务 */
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
        ? (typeof form.bodyTemplate === 'string' ? JSON.parse(form.bodyTemplate) : form.bodyTemplate)
        : null,
      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 ? [form.stepConcurrency] : null,
      stepDuration: form.mode === 'step' ? (form.stepDuration || 30) : null,
      authRequired: form.authRequired,
      accountKey: form.authRequired ? form.accountKey : null,
      signRequest: form.signRequest,
      assertions: [],
      presetId: form.presetId || null,
    }

    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;
}

/* 预设摘要卡片 */
.preset-summary {
  margin-bottom: 16px;
  background: #fafafa;
}

.preset-summary-header {
  display: flex;
  align-items: center;
  gap: 8px;
}

.preset-summary-title {
  font-weight: 600;
  font-size: 14px;
}

.preset-summary-body {
  font-size: 13px;
  line-height: 1.8;
  position: relative;
  padding-right: 120px;
}

.preset-summary-body code {
  word-break: break-all;
  font-size: 12px;
}

.preset-summary-clear {
  position: absolute;
  right: 0;
  top: 0;
}

.preset-body-view {
  width: 100%;
  max-height: 90px;
  overflow: auto;
  background: #f5f7fa;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  padding: 6px 10px;
  font-size: 12px;
}

.preset-body-view pre {
  margin: 0;
  color: #606266;
}
</style>