<!--
  组件名称：ProjectDetail.vue
  组件描述：性能测试项目详情页（任务列表 + 复选框批量执行 + WebSocket 进度）

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

<template>
  <div class="project-detail-page">
    <!-- 返回按钮 + 项目信息头部 -->
    <div class="page-header">
      <div class="header-left">
        <el-button @click="goBack" text>
          <el-icon><ArrowLeft /></el-icon>返回
        </el-button>
        <h2 class="project-title">{{ project?.name || '项目加载中...' }}</h2>
        <el-tag v-if="project" size="small" :type="project.projectType === 'standard' ? 'info' : 'warning'">
          {{ project.projectType === 'standard' ? '标准版' : '项目定制' }}
        </el-tag>
      </div>
      <div class="header-right">
        <el-button type="primary" :loading="runningAll" @click="handleRunAll">
          <el-icon><VideoPlay /></el-icon>执行全部
        </el-button>
        <el-button v-if="selectedIds.length > 0" type="warning" :loading="runningBatch" @click="handleBatchRun">
          <el-icon><VideoPlay /></el-icon>批量执行（{{ selectedIds.length }}）
        </el-button>
        <el-button @click="loadTasks">
          <el-icon><Refresh /></el-icon>刷新
        </el-button>
      </div>
    </div>

    <!-- 项目描述 -->
    <div v-if="project?.description" class="project-desc-bar">
      {{ project.description }}
    </div>

    <!-- 批量执行进度条 -->
    <el-card v-if="batchProgressVisible" shadow="never" class="batch-progress-card">
      <template #header>
        <div class="batch-progress-header">
          <span>批量执行进度</span>
          <el-button text size="small" @click="batchProgressVisible = false">关闭</el-button>
        </div>
      </template>
      <div class="batch-progress-body">
        <div class="batch-progress-info">
          <span>正在执行：{{ batchCurrentTaskName }}</span>
          <span class="batch-progress-count">
            成功 {{ batchSuccessCount }} / 失败 {{ batchFailCount }}
          </span>
        </div>
        <el-progress
          :percentage="batchProgressPercent"
          :status="batchProgressStatus"
          :stroke-width="16"
          :text-inside="true"
        />
        <div class="batch-progress-text">
          第 {{ batchCurrentIndex }} / {{ batchTotalCount }} 个任务
        </div>
      </div>
    </el-card>

    <!-- 任务列表 -->
    <el-card shadow="never">
      <div class="toolbar">
        <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>
      </div>

      <el-table
        ref="tableRef"
        :data="tasks"
        v-loading="loading"
        stripe
        style="width: 100%"
        @selection-change="onSelectionChange"
      >
        <el-table-column type="selection" width="50" />
        <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-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>
  </div>
</template>

<script setup lang="ts">
/**
 * 性能测试项目详情页
 *
 * 功能：
 * 1. 项目信息展示 + 返回按钮
 * 2. 任务列表（带复选框，按项目过滤）
 * 3. 执行全部（runProjectAll）
 * 4. 批量执行选中任务（batchRunTasks）
 * 5. WebSocket 批量执行进度条
 * 6. 单任务执行/停止/删除/跳转监控报告
 */

import { ref, onMounted, onUnmounted, computed } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { ArrowLeft, VideoPlay, Refresh } from '@element-plus/icons-vue'
import { getProject, listTasks, runTask, stopTask, deleteTask, runProjectAll, batchRunTasks } from '@/api/performance'
import type { PerformanceProject, PerformanceTaskListItem } from '@/types/performance'

const router = useRouter()
const route = useRoute()

// ==================== 响应式数据 ====================
const projectId = computed(() => route.params.id as string)

const loading = ref(false)
const project = ref<PerformanceProject | null>(null)
const tasks = ref<PerformanceTaskListItem[]>([])
const total = ref(0)
const page = ref(1)
const pageSize = ref(20)
const statusFilter = ref('')
const runningId = ref('')
const runningAll = ref(false)
const runningBatch = ref(false)

// 复选框选中
const selectedIds = ref<string[]>([])
const tableRef = ref()

// 批量执行进度
const batchProgressVisible = ref(false)
const batchCurrentIndex = ref(0)
const batchTotalCount = ref(0)
const batchCurrentTaskName = ref('')
const batchSuccessCount = ref(0)
const batchFailCount = ref(0)
const batchProgressPercent = computed(() => {
  if (batchTotalCount.value === 0) return 0
  return Math.round((batchCurrentIndex.value / batchTotalCount.value) * 100)
})
const batchProgressStatus = computed(() => {
  if (batchFailCount.value > 0) return 'exception'
  if (batchProgressPercent.value >= 100) return 'success'
  return ''
})

// WebSocket 实例
let ws: WebSocket | null = null

// ==================== 方法定义 ====================

/** 返回项目管理页 */
function goBack() {
  router.push('/performance/projects')
}

/** 加载项目信息 */
async function loadProject() {
  if (!projectId.value) return
  try {
    project.value = await getProject(projectId.value)
  } catch (e: any) {
    ElMessage.error('加载项目信息失败: ' + (e.response?.data?.detail || e.message || ''))
  }
}

/** 加载任务列表（按项目过滤） */
async function loadTasks() {
  if (!projectId.value) return
  loading.value = true
  try {
    const params: any = { page: page.value, pageSize: pageSize.value, projectId: projectId.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 onSelectionChange(selection: PerformanceTaskListItem[]) {
  selectedIds.value = selection.map(t => t.id)
}

/** 执行单个任务 */
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 || ''))
  }
}

/** 执行全部 */
async function handleRunAll() {
  const confirmed = await ElMessageBox.confirm(
    `确定要执行项目"${project.value?.name}"下的全部任务吗？`,
    '确认执行',
    { type: 'warning' }
  ).catch(() => null)
  if (confirmed === null) return

  runningAll.value = true
  showBatchProgress(tasks.value.length)
  try {
    const res = await runProjectAll(projectId.value)
    ElMessage.success(res.message || '项目已开始执行')
  } catch (e: any) {
    ElMessage.error('执行失败: ' + (e.response?.data?.detail || e.message || ''))
  } finally {
    runningAll.value = false
  }
}

/** 批量执行选中任务 */
async function handleBatchRun() {
  if (selectedIds.value.length === 0) {
    ElMessage.warning('请至少选择一个任务')
    return
  }

  const confirmed = await ElMessageBox.confirm(
    `确定要批量执行选中的 ${selectedIds.value.length} 个任务吗？`,
    '确认执行',
    { type: 'warning' }
  ).catch(() => null)
  if (confirmed === null) return

  runningBatch.value = true
  showBatchProgress(selectedIds.value.length)
  try {
    const res = await batchRunTasks({ taskIds: selectedIds.value, projectId: projectId.value })
    ElMessage.success(res.message || '批量执行完成')
    selectedIds.value = []
    tableRef.value?.clearSelection()
    await loadTasks()
  } catch (e: any) {
    ElMessage.error('批量执行失败: ' + (e.response?.data?.detail || e.message || ''))
  } finally {
    runningBatch.value = false
  }
}

/** 显示批量执行进度条连接 WebSocket */
function showBatchProgress(totalCount: number) {
  batchProgressVisible.value = true
  batchCurrentIndex.value = 0
  batchTotalCount.value = totalCount
  batchCurrentTaskName.value = '准备中...'
  batchSuccessCount.value = 0
  batchFailCount.value = 0

  // 连接 WebSocket 监听批量进度
  connectBatchWs()
}

/** 连接 WebSocket 监听批量执行进度 */
function connectBatchWs() {
  const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
  const host = window.location.host
  const wsUrl = `${protocol}//${host}/api/performance/ws/batch-progress`

  ws = new WebSocket(wsUrl)

  ws.onmessage = (event) => {
    try {
      const msg = JSON.parse(event.data)
      if (msg.type === 'perf_batch_progress') {
        batchCurrentIndex.value = msg.currentIndex
        batchTotalCount.value = msg.totalCount
        batchCurrentTaskName.value = msg.currentTaskName || ''
        batchSuccessCount.value = msg.successCount || 0
        batchFailCount.value = msg.failCount || 0
      }
    } catch {
      // 忽略解析错误
    }
  }

  ws.onerror = () => {
    // WebSocket 连接失败不影响主流程
  }

  ws.onclose = () => {
    ws = null
  }
}

/** 状态标签类型 */
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(() => {
  loadProject()
  loadTasks()
})

onUnmounted(() => {
  // 关闭 WebSocket 连接
  if (ws) {
    ws.close()
    ws = null
  }
})
</script>

<style scoped>
.project-detail-page {
  padding: 0;
}

.page-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;

  .header-left {
    display: flex;
    align-items: center;
    gap: 12px;

    .project-title {
      font-size: 20px;
      font-weight: 600;
      color: #303133;
      margin: 0;
    }
  }

  .header-right {
    display: flex;
    gap: 12px;
  }
}

.project-desc-bar {
  background: #f0f5ff;
  border: 1px solid #d6e4ff;
  border-radius: 4px;
  padding: 10px 16px;
  margin-bottom: 16px;
  font-size: 13px;
  color: #606266;
  line-height: 1.6;
}

.batch-progress-card {
  margin-bottom: 16px;
  background: #fafafa;

  .batch-progress-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-weight: 600;
    font-size: 14px;
  }

  .batch-progress-body {
    .batch-progress-info {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 10px;
      font-size: 13px;
      color: #606266;

      .batch-progress-count {
        color: #909399;
      }
    }

    .batch-progress-text {
      margin-top: 6px;
      font-size: 12px;
      color: #909399;
      text-align: right;
    }
  }
}

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

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