<!--
  页面名称：Reports.vue
  页面描述：报告中心页面，展示已完成执行记录并支持生成/导出报告
             支持 UI 自动化报告（HTML iframe）和安全测试报告（Markdown 渲染）

  @author czj
  @date 2026-07-09
  @last-modified 2026-07-22
-->

<template>
  <div class="reports-page">
    <!-- 页面头部 -->
    <div class="page-header">
      <h2>报告中心</h2>
      <el-button @click="loadReports">
        <el-icon><Refresh /></el-icon>
        刷新
      </el-button>
    </div>

    <!-- 报告列表 -->
    <el-card class="reports-list" shadow="never">
      <el-table
        :data="reports"
        stripe
        style="width: 100%"
        v-loading="loading"
      >
        <el-table-column prop="name" label="执行名称" min-width="200" />
        <el-table-column label="报告类型" width="120">
          <template #default="{ row }">
            <el-tag :type="reportTypeTag(row.case_type)" size="small">
              {{ reportTypeLabel(row.case_type) }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="通过率" width="120">
          <template #default="{ row }">
            <div class="pass-rate-cell">
              <span :class="getPassRateClass(row.pass_rate)">
                {{ row.pass_rate }}%
              </span>
              <el-progress
                :percentage="row.pass_rate"
                :stroke-width="8"
                :color="getProgressColor(row.pass_rate)"
                :show-text="false"
                style="width: 60px"
              />
            </div>
          </template>
        </el-table-column>
        <el-table-column label="通过/失败/总数" width="180">
          <template #default="{ row }">
            <div class="count-cell">
              <span class="count-passed">{{ row.passed }}</span>
              <span class="count-sep">/</span>
              <span class="count-failed">{{ row.failed }}</span>
              <span class="count-sep">/</span>
              <span class="count-total">{{ row.total_cases }}</span>
            </div>
          </template>
        </el-table-column>
        <el-table-column label="耗时" width="100">
          <template #default="{ row }">
            {{ row.duration?.toFixed(1) || 0 }}s
          </template>
        </el-table-column>
        <el-table-column label="执行时间" width="180">
          <template #default="{ row }">
            {{ formatTime(row.created_at) }}
          </template>
        </el-table-column>
        <el-table-column label="操作" width="200" fixed="right">
          <template #default="{ row }">
            <el-button size="small" type="primary" link @click="viewReport(row)">
              <el-icon><View /></el-icon>
              查看报告
            </el-button>
            <el-button size="small" type="primary" link @click="downloadReport(row)">
              <el-icon><Files /></el-icon>
              下载
            </el-button>
          </template>
        </el-table-column>
      </el-table>

      <div class="pagination">
        <el-pagination
          v-model:current-page="currentPage"
          v-model:page-size="pageSize"
          :total="total"
          layout="total, prev, pager, next"
          @current-change="loadReports"
        />
      </div>
    </el-card>

    <!-- UI 自动化报告预览弹窗 -->
    <el-dialog
      v-model="previewDialogVisible"
      title="UI 自动化测试报告"
      width="90%"
      top="5vh"
      destroy-on-close
      fullscreen
    >
      <div class="report-preview-container">
        <iframe
          v-if="previewUrl"
          :src="previewUrl"
          class="report-iframe"
          sandbox="allow-same-origin allow-scripts"
        />
        <el-empty v-else description="报告加载失败" />
      </div>
    </el-dialog>

    <!-- 安全测试报告预览弹窗 -->
    <el-dialog
      v-model="securityPreviewVisible"
      title="安全测试报告"
      width="90%"
      top="5vh"
      destroy-on-close
      fullscreen
    >
      <template #header>
        <div class="security-report-header">
          <span>安全测试报告</span>
          <el-button type="primary" size="small" @click="downloadSecurityReport">
            <el-icon><Download /></el-icon>
            下载报告
          </el-button>
        </div>
      </template>
      <div class="security-report-container" v-loading="loadingSecurity">
        <div
          v-if="securityReportContent"
          class="markdown-body"
          v-html="renderedMarkdown"
        />
        <el-empty v-else-if="!loadingSecurity" description="报告加载失败" />
      </div>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
/**
 * 报告中心页面
 *
 * 功能：
 * 1. 展示已完成执行记录列表（支持 UI 自动化和安全测试）
 * 2. 预览 UI 自动化报告（HTML iframe）
 * 3. 预览安全测试报告（Markdown 渲染）
 * 4. 下载报告文件
 */

import { ref, computed, watch, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { ElMessage } from 'element-plus'
import { Refresh, View, Download, Files } from '@element-plus/icons-vue'
import { marked } from 'marked'
import { reportApi } from '@/api/reports'
import { getSecurityReport, getSecurityReportDownloadUrl } from '@/api/security'

const route = useRoute()

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

const loading = ref(false)
const reports = ref<any[]>([])
const total = ref(0)
const currentPage = ref(1)
const pageSize = ref(20)

// UI 自动化报告预览
const previewDialogVisible = ref(false)
const previewUrl = ref('')

// 安全测试报告预览
const securityPreviewVisible = ref(false)
const securityReportContent = ref('')
const loadingSecurity = ref(false)
const currentSecurityExecutionId = ref('')

/** 当前用例类型（来自路由参数，默认 ui） */
const currentType = computed(() => (route.params.type as string) || 'ui')

/** 报告类型标签映射 */
const REPORT_TYPE_LABELS: Record<string, string> = {
  ui: 'UI自动化测试',
  api: '接口测试',
  security: '安全测试',
  functional: '功能测试报告',
}
const REPORT_TYPE_TAGS: Record<string, string> = {
  ui: 'primary',
  api: 'success',
  security: 'danger',
  functional: 'warning',
}
const reportTypeLabel = (type: string) => REPORT_TYPE_LABELS[type] || type
const reportTypeTag = (type: string) => REPORT_TYPE_TAGS[type] || 'info'

/** 渲染后的 Markdown */
const renderedMarkdown = computed(() => {
  if (!securityReportContent.value) return ''
  return marked.parse(securityReportContent.value) as string
})

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

const loadReports = async () => {
  loading.value = true
  try {
    const response = await reportApi.list({
      skip: (currentPage.value - 1) * pageSize.value,
      limit: pageSize.value,
      case_type: currentType.value,
    })
    reports.value = response.items
    total.value = response.total
  } catch (error: any) {
    ElMessage.error('加载报告列表失败: ' + error.message)
  } finally {
    loading.value = false
  }
}

const getPassRateClass = (rate: number) => {
  if (rate >= 90) return 'rate-success'
  if (rate >= 70) return 'rate-warning'
  return 'rate-danger'
}

const getProgressColor = (rate: number) => {
  if (rate >= 90) return '#67c23a'
  if (rate >= 70) return '#e6a23c'
  return '#f56c6c'
}

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

/**
 * 查看报告
 * - UI 自动化报告：iframe 预览 HTML
 * - 安全测试报告：Markdown 渲染
 */
const viewReport = async (row: any) => {
  if (row.case_type === 'security') {
    // 安全测试报告 - Markdown 渲染
    currentSecurityExecutionId.value = row.id
    securityReportContent.value = ''
    securityPreviewVisible.value = true
    loadingSecurity.value = true

    try {
      const response = await getSecurityReport(row.id)
      securityReportContent.value = response.data.content
    } catch (error: any) {
      ElMessage.error('加载安全测试报告失败: ' + error.message)
      securityReportContent.value = ''
    } finally {
      loadingSecurity.value = false
    }
  } else {
    // UI 自动化报告 - iframe 预览
    previewUrl.value = reportApi.generateUrl(row.id)
    previewDialogVisible.value = true
  }
}

/**
 * 下载报告
 * - UI 自动化报告：下载 HTML 文件
 * - 安全测试报告：下载 Markdown 文件
 */
const downloadReport = (row: any) => {
  if (row.case_type === 'security') {
    // 安全测试报告 - 下载 Markdown
    const url = getSecurityReportDownloadUrl(row.id)
    window.open(url, '_blank')
  } else {
    // UI 自动化报告 - 下载 HTML
    const url = reportApi.downloadUrl(row.id)
    window.open(url, '_blank')
  }
}

/**
 * 下载安全测试报告（弹窗内按钮）
 */
const downloadSecurityReport = () => {
  if (currentSecurityExecutionId.value) {
    const url = getSecurityReportDownloadUrl(currentSecurityExecutionId.value)
    window.open(url, '_blank')
  }
}

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

onMounted(() => {
  loadReports()
})

// 路由类型变化时重新加载（切换报告类型子菜单）
watch(currentType, () => {
  currentPage.value = 1
  loadReports()
})
</script>

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

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

  .reports-list {
    .pass-rate-cell {
      display: flex;
      align-items: center;
      gap: 8px;
    }

    .count-cell {
      font-size: 13px;

      .count-passed { color: #67c23a; font-weight: 600; }
      .count-sep { color: #909399; margin: 0 2px; }
      .count-failed { color: #f56c6c; font-weight: 600; }
      .count-total { color: #606266; }
    }

    .rate-success { color: #67c23a; font-weight: 600; }
    .rate-warning { color: #e6a23c; font-weight: 600; }
    .rate-danger { color: #f56c6c; font-weight: 600; }

    .pagination {
      margin-top: 20px;
      display: flex;
      justify-content: flex-end;
    }
  }

  .report-preview-container {
    height: calc(100vh - 200px);

    .report-iframe {
      width: 100%;
      height: 100%;
      border: none;
      border-radius: 4px;
    }
  }

  // 安全测试报告样式
  .security-report-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
  }

  .security-report-container {
    height: calc(100vh - 200px);
    overflow-y: auto;
    padding: 20px;
    background-color: var(--el-bg-color);
    border-radius: 4px;
  }
}

// Markdown 样式（GitHub 风格）
.markdown-body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif;
  font-size: 14px;
  line-height: 1.6;
  color: var(--el-text-color-primary);

  :deep(h1) {
    font-size: 2em;
    font-weight: 600;
    padding-bottom: 0.3em;
    border-bottom: 1px solid var(--el-border-color);
    margin-top: 24px;
    margin-bottom: 16px;
  }

  :deep(h2) {
    font-size: 1.5em;
    font-weight: 600;
    padding-bottom: 0.3em;
    border-bottom: 1px solid var(--el-border-color);
    margin-top: 24px;
    margin-bottom: 16px;
  }

  :deep(h3) {
    font-size: 1.25em;
    font-weight: 600;
    margin-top: 24px;
    margin-bottom: 16px;
  }

  :deep(h4) {
    font-size: 1em;
    font-weight: 600;
    margin-top: 24px;
    margin-bottom: 16px;
  }

  :deep(p) {
    margin-bottom: 16px;
  }

  :deep(table) {
    border-collapse: collapse;
    width: 100%;
    margin-bottom: 16px;

    th, td {
      padding: 8px 13px;
      border: 1px solid var(--el-border-color);
    }

    th {
      font-weight: 600;
      background-color: var(--el-fill-color-light);
    }

    tr:nth-child(2n) {
      background-color: var(--el-fill-color-lighter);
    }
  }

  :deep(code) {
    padding: 0.2em 0.4em;
    margin: 0;
    font-size: 85%;
    font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;
    background-color: var(--el-fill-color-light);
    border-radius: 6px;
  }

  :deep(pre) {
    padding: 16px;
    overflow: auto;
    font-size: 85%;
    line-height: 1.45;
    background-color: var(--el-fill-color-light);
    border-radius: 6px;
    margin-bottom: 16px;

    code {
      padding: 0;
      background-color: transparent;
    }
  }

  :deep(ul), :deep(ol) {
    padding-left: 2em;
    margin-bottom: 16px;
  }

  :deep(li) {
    margin-bottom: 4px;
  }

  :deep(blockquote) {
    padding: 0 1em;
    color: var(--el-text-color-secondary);
    border-left: 0.25em solid var(--el-border-color);
    margin-bottom: 16px;
  }

  :deep(hr) {
    height: 0.25em;
    padding: 0;
    margin: 24px 0;
    background-color: var(--el-border-color);
    border: 0;
  }

  :deep(a) {
    color: var(--el-color-primary);
    text-decoration: none;

    &:hover {
      text-decoration: underline;
    }
  }

  :deep(img) {
    max-width: 100%;
    height: auto;
  }

  // 特殊样式：OWASP 矩阵表格
  :deep(.owasp-matrix) {
    text-align: center;

    td:first-child {
      text-align: left;
    }
  }
}
</style>
