<!--
  组件名称：StepDetailPanel.vue
  组件描述：步骤详情组件，展示步骤列表、截图、日志和错误详情

  @author czj
  @date 2026-07-09
-->

<template>
  <div class="step-detail-panel">
    <!-- 步骤概览统计 -->
    <div class="step-summary">
      <div class="summary-item" v-for="item in summaryStats" :key="item.label">
        <span class="summary-value" :class="item.class">{{ item.count }}</span>
        <span class="summary-label">{{ item.label }}</span>
      </div>
    </div>

    <!-- 步骤列表 -->
    <div class="step-list">
      <el-timeline>
        <el-timeline-item
          v-for="step in steps"
          :key="step.order"
          :timestamp="step.duration ? `${step.duration.toFixed(2)}s` : ''"
          :color="getStepColor(step.status)"
          placement="top"
          :hollow="step.status !== 'failed'"
        >
          <div class="step-item" :class="`step-${step.status}`">
            <div class="step-header">
              <span class="step-order">#{{ step.order }}</span>
              <span class="step-name">{{ step.name || step.action }}</span>
              <el-tag :type="getStepTagType(step.status)" size="small" effect="plain">
                {{ getStepStatusText(step.status) }}
              </el-tag>
            </div>

            <div class="step-meta">
              <span class="meta-action">动作: {{ step.action }}</span>
              <span class="meta-selector" v-if="step.selector">选择器: <code>{{ step.selector }}</code></span>
            </div>

            <!-- 步骤操作按钮 -->
            <div class="step-actions">
              <el-button
                size="small"
                type="primary"
                link
                @click="toggleLog(step.order)"
                v-if="step.log"
              >
                <el-icon><Document /></el-icon>
                日志
              </el-button>
              <el-button
                size="small"
                type="primary"
                link
                @click="viewScreenshot(step.screenshot)"
                v-if="step.screenshot"
              >
                <el-icon><Picture /></el-icon>
                截图
              </el-button>
              <el-button
                size="small"
                type="danger"
                link
                @click="toggleError(step.order)"
                v-if="step.error"
              >
                <el-icon><Warning /></el-icon>
                错误详情
              </el-button>
            </div>

            <!-- 日志内容区 -->
            <div class="step-log" v-if="expandedLogs[step.order]">
              <div class="log-header">
                <el-icon :size="16"><Document /></el-icon>
                <span>执行日志</span>
              </div>
              <pre class="log-content">{{ step.log }}</pre>
            </div>

            <!-- 错误详情区 -->
            <div class="step-error" v-if="expandedErrors[step.order]">
              <div class="error-header">
                <el-icon :size="16"><WarningFilled /></el-icon>
                <span>错误详情</span>
              </div>
              <pre class="error-content">{{ step.error }}</pre>
            </div>

            <!-- 截图预览 -->
            <div class="step-screenshot" v-if="step.screenshot && viewingScreenshot.has(step.screenshot)">
              <el-image
                :src="getScreenshotUrl(step.screenshot)"
                fit="contain"
                :preview-src-list="[getScreenshotUrl(step.screenshot)]"
                preview-teleported
                style="max-height: 300px; width: 100%"
              >
                <template #error>
                  <div class="screenshot-error">
                    <el-icon :size="32"><PictureFilled /></el-icon>
                    <span>截图加载失败</span>
                  </div>
                </template>
              </el-image>
            </div>
          </div>
        </el-timeline-item>
      </el-timeline>

      <el-empty v-if="!steps || steps.length === 0" description="暂无步骤数据" :image-size="60" />
    </div>
  </div>
</template>

<script setup lang="ts">
/**
 * 步骤详情组件
 *
 * 功能：
 * 1. 步骤列表展示（时间线形式）
 * 2. 步骤状态标识（通过/失败/跳过）
 * 3. 截图展示和预览
 * 4. 执行日志查看器
 * 5. 错误详情展开
 * 6. 统计概览
 */

import { ref, computed } from 'vue'
import { Document, Picture, Warning, WarningFilled, PictureFilled } from '@element-plus/icons-vue'

interface StepResult {
  order: number
  name: string
  action: string
  selector?: string
  status: string
  duration?: number
  screenshot?: string
  log?: string
  error?: string
}

const props = defineProps<{
  steps: StepResult[]
  caseName?: string
  executionId?: string
}>()

// 展开的日志
const expandedLogs = ref<Record<number, boolean>>({})
// 展开的错误
const expandedErrors = ref<Record<number, boolean>>({})
// 当前查看的截图（默认展开所有有截图的步骤）
const viewingScreenshot = ref<Set<string>>(
  new Set(props.steps.filter(s => s.screenshot).map(s => s.screenshot!))
)

// 统计概览
const summaryStats = computed(() => {
  const total = props.steps.length
  const passed = props.steps.filter(s => s.status === 'passed').length
  const failed = props.steps.filter(s => s.status === 'failed').length
  const skipped = props.steps.filter(s => s.status === 'skipped').length

  return [
    { label: '总步骤', count: total, class: '' },
    { label: '通过', count: passed, class: 'count-passed' },
    { label: '失败', count: failed, class: 'count-failed' },
    { label: '跳过', count: skipped, class: 'count-skipped' },
  ]
})

const getStepColor = (status: string) => {
  const map: Record<string, string> = {
    passed: '#67c23a',
    failed: '#f56c6c',
    skipped: '#909399',
    running: '#409eff',
    pending: '#e6e6e6',
  }
  return map[status] || '#e6e6e6'
}

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

const getStepStatusText = (status: string) => {
  const map: Record<string, string> = {
    passed: '通过',
    failed: '失败',
    skipped: '跳过',
    running: '执行中',
    pending: '待执行',
  }
  return map[status] || status
}

const toggleLog = (order: number) => {
  expandedLogs.value[order] = !expandedLogs.value[order]
  // 展开日志时收起错误
  if (expandedLogs.value[order]) {
    delete expandedErrors.value[order]
  }
}

const toggleError = (order: number) => {
  expandedErrors.value[order] = !expandedErrors.value[order]
  // 展开错误时收起日志
  if (expandedErrors.value[order]) {
    delete expandedLogs.value[order]
  }
}

const viewScreenshot = (screenshot: string) => {
  if (viewingScreenshot.value.has(screenshot)) {
    viewingScreenshot.value.delete(screenshot)
  } else {
    viewingScreenshot.value.add(screenshot)
  }
  // 触发响应式更新（Set 的 add/delete 不触发 ref 响应）
  viewingScreenshot.value = new Set(viewingScreenshot.value)
}

const getScreenshotUrl = (screenshot: string) => {
  // 如果已经是完整 URL 则直接返回
  if (screenshot.startsWith('http://') || screenshot.startsWith('https://') || screenshot.startsWith('data:')) {
    return screenshot
  }
  // 否则拼接 API 地址
  return `/api/files/${screenshot.replace(/\\/g, '/')}`
}
</script>

<style lang="scss" scoped>
.step-detail-panel {
  .step-summary {
    display: flex;
    gap: 20px;
    margin-bottom: 24px;
    padding: 16px 20px;
    background: #f5f7fa;
    border-radius: 8px;

    .summary-item {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 4px;

      .summary-value {
        font-size: 28px;
        font-weight: 700;
        color: #303133;

        &.count-passed { color: #67c23a; }
        &.count-failed { color: #f56c6c; }
        &.count-skipped { color: #909399; }
      }

      .summary-label {
        font-size: 13px;
        color: #909399;
      }
    }
  }

  .step-list {
    .step-item {
      padding: 8px 0;

      .step-header {
        display: flex;
        align-items: center;
        gap: 12px;
        margin-bottom: 4px;

        .step-order {
          font-size: 13px;
          font-weight: 600;
          color: #909399;
          min-width: 24px;
        }

        .step-name {
          font-size: 15px;
          font-weight: 500;
          color: #303133;
          flex: 1;
        }
      }

      .step-meta {
        display: flex;
        gap: 16px;
        margin-bottom: 8px;
        font-size: 12px;
        color: #909399;

        .meta-selector {
          code {
            background: #f5f7fa;
            padding: 1px 6px;
            border-radius: 3px;
            font-size: 12px;
            color: #606266;
          }
        }
      }

      .step-actions {
        display: flex;
        gap: 8px;
        margin-bottom: 4px;
      }

      /* 日志区域 */
      .step-log {
        margin-top: 8px;
        background: #1e1e1e;
        border-radius: 6px;
        overflow: hidden;

        .log-header {
          display: flex;
          align-items: center;
          gap: 6px;
          padding: 8px 12px;
          background: #2d2d2d;
          color: #e0e0e0;
          font-size: 13px;
          font-weight: 500;
        }

        .log-content {
          margin: 0;
          padding: 12px;
          font-size: 12px;
          line-height: 1.6;
          color: #d4d4d4;
          max-height: 200px;
          overflow-y: auto;
          white-space: pre-wrap;
          word-break: break-all;
          font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
        }
      }

      /* 错误区域 */
      .step-error {
        margin-top: 8px;
        background: #fef0f0;
        border: 1px solid #fde2e2;
        border-radius: 6px;
        overflow: hidden;

        .error-header {
          display: flex;
          align-items: center;
          gap: 6px;
          padding: 8px 12px;
          background: #fde2e2;
          color: #f56c6c;
          font-size: 13px;
          font-weight: 500;
        }

        .error-content {
          margin: 0;
          padding: 12px;
          font-size: 13px;
          line-height: 1.6;
          color: #f56c6c;
          max-height: 200px;
          overflow-y: auto;
          white-space: pre-wrap;
          word-break: break-all;
          font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
        }
      }

      /* 截图区域 */
      .step-screenshot {
        margin-top: 8px;
        border: 1px solid #e4e7ed;
        border-radius: 6px;
        overflow: hidden;
        background: #fafafa;

        .screenshot-error {
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
          height: 200px;
          gap: 8px;
          color: #909399;
        }
      }
    }
  }
}
</style>