<template>
  <div class="session-wrap">
    <!-- 顶部导航 -->
    <div class="top-bar">
      <el-button text @click="router.push('/')">
        <el-icon><ArrowLeft /></el-icon> 返回首页
      </el-button>
      <span class="session-id">会话 {{ sessionId.slice(0, 8) }}…</span>
    </div>

    <!-- 步骤条 -->
    <div class="steps-container">
      <el-steps :active="activeStep" finish-status="success" align-center>
        <el-step title="需求确认" :icon="ChatLineRound" />
        <el-step title="PM 分析" :icon="EditPen" />
        <el-step title="QA 用例" :icon="List" />
        <el-step title="Dev 代码" :icon="Monitor" />
        <el-step title="测试执行" :icon="Cpu" />
      </el-steps>
    </div>

    <div class="content-area">
      <!-- ===================== STEP 0: 需求澄清 ===================== -->
      <template v-if="activeStep === 0">
        <el-card class="step-card" shadow="never">
          <template #header>
            <div class="card-header">
              <el-icon color="#409eff"><ChatLineRound /></el-icon>
              <span>需求澄清</span>
              <el-tag :type="statusTagType" size="small">{{ statusLabel }}</el-tag>
            </div>
          </template>

          <!-- 需求原文 -->
          <div class="req-block">
            <div class="block-label">📋 原始需求</div>
            <div class="req-text">{{ rawRequirement }}</div>
          </div>

          <!-- 对话历史 -->
          <div v-if="clarifyHistory.length" class="chat-history">
            <div
              v-for="(msg, i) in clarifyHistory"
              :key="i"
              :class="['chat-msg', msg.role]"
            >
              <div class="chat-bubble">{{ msg.content }}</div>
              <div class="chat-role">{{ msg.role === 'assistant' ? '🤖 AI' : '👤 您' }}</div>
            </div>
          </div>

          <!-- AI 追问区域 -->
          <template v-if="status === 'clarifying'">
            <el-divider />
            <div class="block-label" style="margin-bottom:12px">💬 请回答 AI 的问题：</div>
            <el-input
              v-model="clarifyInput"
              type="textarea"
              :rows="3"
              placeholder="请输入您的补充说明…"
              :disabled="loading"
            />
            <div class="btn-row">
              <el-button type="primary" :loading="loading" @click="handleClarify">
                发送
              </el-button>
            </div>
          </template>

          <!-- 需求已确认，可进入下一步 -->
          <template v-if="status === 'pm_ready' || status === 'pm_done' || status === 'qa_done' || status === 'dev_done'">
            <el-alert
              title="需求已确认，可以开始 PM 需求分析"
              type="success"
              show-icon
              :closable="false"
              style="margin-top:16px"
            />
            <div class="btn-row" style="margin-top:16px">
              <el-button type="primary" :loading="loading" @click="handlePmRun">
                开始 PM 分析 →
              </el-button>
            </div>
          </template>
        </el-card>
      </template>

      <!-- ===================== STEP 1: PM 分析 ===================== -->
      <template v-if="activeStep === 1">
        <el-card class="step-card" shadow="never">
          <template #header>
            <div class="card-header">
              <el-icon color="#e6a23c"><EditPen /></el-icon>
              <span>PM 需求分析</span>
              <el-tag :type="statusTagType" size="small">{{ statusLabel }}</el-tag>
            </div>
          </template>

          <div v-if="streaming" class="thinking-card">
            <div class="thinking-header">
              <span class="thinking-dots"><span></span><span></span><span></span></span>
              <span class="thinking-title">PM Agent 正在分析需求…</span>
              <span class="thinking-count">{{ streamText.length }} 字符</span>
            </div>
            <div class="stream-sections-body" ref="pmStreamBodyRef">
              <section v-if="pmStreamParsed.functional_requirements.items.length || pmStreamParsed.currentSection === 'functional_requirements'"
                class="stream-section" :class="{ 'stream-section--active': pmStreamParsed.currentSection === 'functional_requirements' }">
                <div class="stream-section-title">🔧 功能需求</div>
                <ul class="stream-list">
                  <li v-for="(item, i) in pmStreamParsed.functional_requirements.items" :key="i">
                    {{ item.value }}<span v-if="item.active" class="cursor">|</span>
                  </li>
                </ul>
              </section>
              <section v-if="pmStreamParsed.non_functional_requirements.items.length || pmStreamParsed.currentSection === 'non_functional_requirements'"
                class="stream-section" :class="{ 'stream-section--active': pmStreamParsed.currentSection === 'non_functional_requirements' }">
                <div class="stream-section-title">⚙️ 非功能需求</div>
                <ul class="stream-list">
                  <li v-for="(item, i) in pmStreamParsed.non_functional_requirements.items" :key="i">
                    {{ item.value }}<span v-if="item.active" class="cursor">|</span>
                  </li>
                </ul>
              </section>
              <section v-if="pmStreamParsed.acceptance_criteria.items.length || pmStreamParsed.currentSection === 'acceptance_criteria'"
                class="stream-section" :class="{ 'stream-section--active': pmStreamParsed.currentSection === 'acceptance_criteria' }">
                <div class="stream-section-title">✅ 验收标准</div>
                <ul class="stream-list">
                  <li v-for="(item, i) in pmStreamParsed.acceptance_criteria.items" :key="i">
                    {{ item.value }}<span v-if="item.active" class="cursor">|</span>
                  </li>
                </ul>
              </section>
              <section v-if="pmStreamParsed.edge_cases.items.length || pmStreamParsed.currentSection === 'edge_cases'"
                class="stream-section" :class="{ 'stream-section--active': pmStreamParsed.currentSection === 'edge_cases' }">
                <div class="stream-section-title">🚧 边界条件</div>
                <ul class="stream-list">
                  <li v-for="(item, i) in pmStreamParsed.edge_cases.items" :key="i">
                    {{ item.value }}<span v-if="item.active" class="cursor">|</span>
                  </li>
                </ul>
              </section>
              <section v-if="pmStreamParsed.summary.value || pmStreamParsed.currentSection === 'summary'"
                class="stream-section" :class="{ 'stream-section--active': pmStreamParsed.currentSection === 'summary' }">
                <div class="stream-section-title">📌 需求总结</div>
                <p class="stream-text-content">{{ pmStreamParsed.summary.value }}<span v-if="pmStreamParsed.summary.active" class="cursor">|</span></p>
              </section>
              <div v-if="!pmStreamParsed.currentSection" class="stream-waiting">
                <span class="thinking-dots"><span></span><span></span><span></span></span>
                <span>等待 AI 开始输出…</span>
              </div>
            </div>
          </div>

          <div v-else-if="loading" class="loading-area">
            <el-icon class="spinning"><Loading /></el-icon>
            <span>PM Agent 正在分析需求，请稍候…</span>
          </div>

          <template v-else-if="requirementAnalysis">
            <!-- 需求总结 -->
            <section v-if="requirementAnalysis.summary" class="result-section">
              <div class="section-title">📌 需求总结</div>
              <p class="section-text">{{ requirementAnalysis.summary }}</p>
            </section>

            <!-- 功能需求 -->
            <section v-if="requirementAnalysis.functional_requirements?.length" class="result-section">
              <div class="section-title">🔧 功能需求</div>
              <ul class="feature-list">
                <li v-for="(f, i) in requirementAnalysis.functional_requirements" :key="i">{{ f }}</li>
              </ul>
            </section>

            <!-- 验收标准 -->
            <section v-if="requirementAnalysis.acceptance_criteria?.length" class="result-section">
              <div class="section-title">✅ 验收标准</div>
              <ul class="feature-list">
                <li v-for="(a, i) in requirementAnalysis.acceptance_criteria" :key="i">{{ a }}</li>
              </ul>
            </section>

            <!-- 非功能需求 -->
            <section v-if="requirementAnalysis.non_functional_requirements?.length" class="result-section">
              <div class="section-title">⚙️ 非功能需求</div>
              <ul class="feature-list">
                <li v-for="(r, i) in requirementAnalysis.non_functional_requirements" :key="i">{{ r }}</li>
              </ul>
            </section>

            <!-- 边界条件 -->
            <section v-if="requirementAnalysis.edge_cases?.length" class="result-section">
              <div class="section-title">🚧 边界条件</div>
              <ul class="feature-list">
                <li v-for="(e, i) in requirementAnalysis.edge_cases" :key="i">{{ e }}</li>
              </ul>
            </section>

            <!-- 反馈行 -->
            <el-divider />
            <div class="feedback-area">
              <div class="block-label">💡 对以上分析有疑问？请提出修改意见：</div>
              <el-input
                v-model="pmFeedback"
                type="textarea"
                :rows="2"
                placeholder="例如：请补充异常情况处理，需要加上限流说明…"
                :disabled="refining"
              />
              <div class="btn-row">
                <el-button :loading="refining" :disabled="!pmFeedback.trim()" @click="handlePmRefine">
                  重新生成
                </el-button>
                <el-button type="primary" :disabled="!!pmFeedback.trim()" @click="handleQaRun">
                  进入 QA 用例生成 →
                </el-button>
              </div>
            </div>
          </template>
        </el-card>
      </template>

      <!-- ===================== STEP 2: QA 测试用例 ===================== -->
      <template v-if="activeStep === 2">
        <el-card class="step-card" shadow="never">
          <template #header>
            <div class="card-header">
              <el-icon color="#67c23a"><List /></el-icon>
              <span>QA 测试用例</span>
              <el-tag :type="statusTagType" size="small">{{ statusLabel }}</el-tag>
            </div>
          </template>

          <div v-if="streaming" class="thinking-card">
            <div class="thinking-header">
              <span class="thinking-dots"><span></span><span></span><span></span></span>
              <span class="thinking-title">QA Agent 正在生成测试用例…</span>
              <span class="thinking-count">{{ qaStreamParsed.testCases.names.length }} 个用例已生成</span>
            </div>
            <div class="stream-sections-body" ref="qaStreamBodyRef">
              <section class="stream-section" :class="{ 'stream-section--active': qaStreamParsed.currentSection === 'test_cases' }">
                <div class="stream-section-title">🧪 测试用例</div>
                <div class="qa-stream-cases">
                  <div v-for="(name, i) in qaStreamParsed.testCases.names" :key="i" class="qa-stream-case-item">
                    <span class="qa-case-badge">TC{{ String(i + 1).padStart(3, '0') }}</span>
                    {{ name }}
                  </div>
                  <div v-if="qaStreamParsed.testCases.active" class="qa-stream-case-writing">
                    <span class="thinking-dots"><span></span><span></span><span></span></span>
                    <span>正在生成下一个用例…</span>
                  </div>
                  <div v-if="!qaStreamParsed.testCases.names.length && !qaStreamParsed.testCases.active" class="stream-waiting">
                    <span class="thinking-dots"><span></span><span></span><span></span></span>
                    <span>等待生成…</span>
                  </div>
                </div>
              </section>
              <section v-if="qaStreamParsed.testStrategy.value"
                class="stream-section" :class="{ 'stream-section--active': qaStreamParsed.currentSection === 'test_strategy' }">
                <div class="stream-section-title">📋 测试策略</div>
                <p class="stream-text-content">{{ qaStreamParsed.testStrategy.value }}<span v-if="qaStreamParsed.testStrategy.active" class="cursor">|</span></p>
              </section>
              <section v-if="qaStreamParsed.coveragePlan.value"
                class="stream-section" :class="{ 'stream-section--active': qaStreamParsed.currentSection === 'coverage_plan' }">
                <div class="stream-section-title">📊 覆盖计划</div>
                <p class="stream-text-content">{{ qaStreamParsed.coveragePlan.value }}<span v-if="qaStreamParsed.coveragePlan.active" class="cursor">|</span></p>
              </section>
            </div>
          </div>

          <div v-else-if="loading" class="loading-area">
            <el-icon class="spinning"><Loading /></el-icon>
            <span>QA Agent 正在生成测试用例，请稍候…</span>
          </div>

          <template v-else-if="testCases?.length">
            <!-- 按类型分组 -->
            <div v-for="(group, type) in groupedTestCases" :key="type" class="test-group">
              <div class="test-group-title">
                {{ typeEmoji[type] || '🧪' }} {{ type }}（{{ group.length }} 个）
              </div>
              <el-table :data="group" border size="small" class="test-table">
                <el-table-column prop="test_id" label="ID" width="70" />
                <el-table-column prop="test_name" label="用例名称" min-width="160" />
                <el-table-column prop="precondition" label="前置条件" min-width="160" />
                <el-table-column label="步骤" min-width="260">
                  <template #default="{ row }">
                    <ol class="step-list">
                      <li v-for="(s, i) in row.steps" :key="i">{{ s }}</li>
                    </ol>
                  </template>
                </el-table-column>
                <el-table-column prop="expected_result" label="预期结果" min-width="200" />
              </el-table>

            </div>

            <!-- 测试策略 / 覆盖计划 -->
            <template v-if="testStrategy || coveragePlan">
              <el-divider />
              <div class="qa-meta-row">
                <div v-if="testStrategy" class="qa-meta-block">
                  <div class="block-label">📋 测试策略</div>
                  <p class="qa-meta-text">{{ testStrategy }}</p>
                </div>
                <div v-if="coveragePlan" class="qa-meta-block">
                  <div class="block-label">📊 覆盖计划</div>
                  <p class="qa-meta-text">{{ coveragePlan }}</p>
                </div>
              </div>
            </template>

            <!-- 反馈行 -->
            <el-divider />
            <div class="feedback-area">
              <div class="block-label">💡 对测试用例有修改意见？</div>
              <el-input
                v-model="qaFeedback"
                type="textarea"
                :rows="2"
                placeholder="例如：请增加并发测试场景，添加输入长度边界测试…"
                :disabled="refining"
              />
              <div class="btn-row">
                <el-button :loading="refining" :disabled="!qaFeedback.trim()" @click="handleQaRefine">
                  重新生成
                </el-button>
                <el-button type="primary" :disabled="!!qaFeedback.trim()" @click="handleDevRun">
                  进入 Dev 代码生成 →
                </el-button>
              </div>
            </div>
          </template>
        </el-card>
      </template>

      <!-- ===================== STEP 3: Dev 代码生成 ===================== -->
      <template v-if="activeStep === 3">
        <el-card class="step-card" shadow="never">
          <template #header>
            <div class="card-header">
              <el-icon color="#909399"><Monitor /></el-icon>
              <span>Dev 代码生成</span>
              <el-tag :type="statusTagType" size="small">{{ statusLabel }}</el-tag>
            </div>
          </template>

          <div v-if="streaming" class="dev-stream-card">
            <div class="thinking-header">
              <span class="thinking-dots"><span></span><span></span><span></span></span>
              <span class="thinking-title">Dev Agent 正在生成代码…</span>
              <span class="thinking-count">{{ streamText.length }} 字符（代码量较大，请耐心等待）</span>
            </div>
            <el-tabs v-model="devStreamTab" type="card" class="code-tabs dev-stream-tabs">
            
              <el-tab-pane label="🐍 业务代码" name="java_code">
                <div class="code-block-wrap" style="padding-top:36px">
                  <div class="code-lang-badge">Python</div>
                  <pre class="code-block dev-stream-code" ref="devCodeRef">{{ devStreamParsed.java_code }}<span v-if="devStreamParsed.currentField === 'java_code'" class="cursor dev-cursor">|</span></pre>
                </div>
              </el-tab-pane>
              <el-tab-pane label="🧪 单元测试" name="unit_tests">
                <div class="code-block-wrap" style="padding-top:36px">
                  <div class="code-lang-badge">Python</div>
                  <pre class="code-block dev-stream-code" ref="devTestsRef">{{ devStreamParsed.unit_tests }}<span v-if="devStreamParsed.currentField === 'unit_tests'" class="cursor dev-cursor">|</span></pre>
                </div>
              </el-tab-pane>
                <el-tab-pane label="📄 实现思路" name="implementation_notes">
                <div class="dev-stream-notes" ref="devNotesRef">
                  {{ devStreamParsed.implementation_notes }}<span v-if="devStreamParsed.currentField === 'implementation_notes'" class="cursor">|</span>
                </div>
              </el-tab-pane>
            </el-tabs>
          </div>

          <div v-else-if="loading" class="loading-area">
            <el-icon class="spinning"><Loading /></el-icon>
            <span>Dev Agent 正在生成代码，请稍候…（通常需要 30–60 秒）</span>
          </div>

          <template v-else-if="codeGeneration">
              <!-- 开发建议 -->
            <section v-if="codeGeneration.implementation_notes" class="result-section">
              <div class="section-title">📝 实现思路</div>
              <ol class="feature-list">
                <li v-for="(line, i) in parseNotes(codeGeneration.implementation_notes)" :key="i">{{ line }}</li>
              </ol>
            </section>


            <!-- 代码 Tabs -->
            <el-tabs v-model="activeCodeTab" type="card" class="code-tabs">
              <el-tab-pane label="业务代码" name="business">
                <div class="code-block-wrap">
                  <div class="code-lang-badge">Python</div>
                  <el-button class="copy-btn" size="small" text @click="copyCode(codeGeneration.java_code)">
                    <el-icon><CopyDocument /></el-icon> 复制
                  </el-button>
                  <pre class="code-block"><code>{{ codeGeneration.java_code }}</code></pre>
                </div>
              </el-tab-pane>
              <el-tab-pane label="单元测试" name="test">
                <div class="code-block-wrap">
                  <div class="code-lang-badge">Python</div>
                  <el-button class="copy-btn" size="small" text @click="copyCode(codeGeneration.unit_tests)">
                    <el-icon><CopyDocument /></el-icon> 复制
                  </el-button>
                  <pre class="code-block"><code>{{ codeGeneration.unit_tests }}</code></pre>
                </div>
              </el-tab-pane>
            </el-tabs>


            <!-- 完成操作 -->
            <div class="btn-row" style="margin-top:24px">
              <el-button type="primary" size="large" :loading="loadingStep === 4" @click="handleTestRun">
                ▶ 执行单元测试
              </el-button>
            </div>
          </template>
        </el-card>
      </template>

      <!-- ===================== STEP 4: 测试执行 ===================== -->
      <template v-if="activeStep === 4">
        <el-card class="step-card" shadow="never">
          <template #header>
            <div class="card-header">
              <el-icon color="#67c23a"><Cpu /></el-icon>
              <span>单元测试执行</span>
              <el-tag :type="statusTagType" size="small">{{ statusLabel }}</el-tag>
            </div>
          </template>

          <div v-if="loading" class="loading-area">
            <el-icon class="spinning"><Loading /></el-icon>
            <span>正在执行单元测试，请稍候…</span>
          </div>

          <template v-else>
            <!-- 无结果时提示 -->
            <div v-if="!testExecution" class="loading-area" style="padding:60px 0">
              <span style="color:#909399">准备就绪，点击执行按钮运行测试</span>
            </div>

            <!-- 有测试结果 -->
            <template v-else>
              <el-alert
                :title="testExecution.success ? `✅ 全部测试通过！共 ${testExecution.total} 个` : `❌ ${testExecution.failed + testExecution.errors} 个测试失败`"
                :type="testExecution.success ? 'success' : 'error'"
                show-icon
                :closable="false"
                style="margin-bottom:16px"
              />
              <div class="stat-row">
                <div class="stat-card">
                  <div class="stat-num" style="color:#67c23a">{{ testExecution.passed }}</div>
                  <div class="stat-label">通过</div>
                </div>
                <div class="stat-card">
                  <div class="stat-num" style="color:#f56c6c">{{ testExecution.failed }}</div>
                  <div class="stat-label">失败</div>
                </div>
                <div class="stat-card">
                  <div class="stat-num" style="color:#e6a23c">{{ testExecution.errors }}</div>
                  <div class="stat-label">错误</div>
                </div>
                <div class="stat-card">
                  <div class="stat-num">{{ testExecution.total }}</div>
                  <div class="stat-label">合计</div>
                </div>
              </div>
              <section class="result-section">
                <div class="section-title">🖥 pytest 输出</div>
                <div class="code-block-wrap">
                  <el-button class="copy-btn" size="small" text @click="copyCode(testExecution.output)">
                    <el-icon><CopyDocument /></el-icon> 复制
                  </el-button>
                  <pre class="code-block" style="max-height:400px;overflow:auto">{{ testExecution.output }}</pre>
                </div>
              </section>
            </template>

            <div class="btn-row" style="margin-top:16px">
              <el-button @click="doTestRun" :loading="loading">🔄 重新运行</el-button>
              <el-button
                v-if="testExecution && !testExecution.success"
                type="warning"
                :loading="refining"
                @click="handleTestFix"
              >🔧 AI 自动修复</el-button>
              <el-button type="success" @click="router.push('/')">✅ 完成，返回首页</el-button>
            </div>
          </template>
        </el-card>
      </template>

      <!-- 错误提示 -->
      <div v-if="errorMsg" style="margin-top:16px">
        <el-alert :title="errorMsg" type="error" show-icon :closable="true" @close="errorMsg=''" />
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, onMounted, nextTick, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import {
  ArrowLeft, ChatLineRound, EditPen, List, Monitor, Cpu,
  Loading, CopyDocument,
} from '@element-plus/icons-vue'
import { sessionApi } from '@/api/session'

const route = useRoute()
const router = useRouter()
const sessionId = route.params.id

// ---- 状态 ----
const status = ref('')
const rawRequirement = ref('')
const clarifyHistory = ref([])
const requirementAnalysis = ref(null)
const testCases = ref([])
const testStrategy = ref('')
const coveragePlan = ref('')
const codeGeneration = ref(null)
const testExecution = ref(null)

const loading = ref(false)
const refining = ref(false)
const streaming = ref(false)
const streamText = ref('')
const errorMsg = ref('')

const clarifyInput = ref('')
const pmFeedback = ref('')
const qaFeedback = ref('')
const devFeedback = ref('')
const activeCodeTab = ref('business')
const devStreamTab = ref('implementation_notes')
const loadingStep = ref(null) // 跨步骤操作时立即更新，避免显示错误的加载状态
const streamContainer = ref(null)
const pmStreamBodyRef = ref(null)
const qaStreamBodyRef = ref(null)
const devNotesRef = ref(null)     // Dev 实现思路容器
const devCodeRef = ref(null)      // Dev 业务代码容器
const devTestsRef = ref(null)     // Dev 单元测试容器

// ---- 计算属性 ----
const activeStep = computed(() => {
  if (loadingStep.value !== null) return loadingStep.value
  const map = {
    clarifying: 0,
    pm_ready: 0,
    pm_done: 1,
    qa_ready: 1,
    qa_done: 2,
    dev_ready: 2,
    dev_done: 3,
    test_done: 4,
  }
  return map[status.value] ?? 0
})

const statusLabel = computed(() => {
  const map = {
    clarifying: '需求追问中',
    pm_ready: '可开始分析',
    pm_done: 'PM 完成',
    qa_ready: '可生成用例',
    qa_done: 'QA 完成',
    dev_ready: '可生成代码',
    dev_done: '代码就绪',
    test_done: '测试完成',
  }
  return map[status.value] || status.value
})

const statusTagType = computed(() => {
  const map = {
    clarifying: 'warning',
    pm_ready: 'info',
    pm_done: '',
    qa_ready: 'info',
    qa_done: '',
    dev_ready: 'info',
    dev_done: '',
    test_done: 'success',
  }
  return map[status.value] ?? ''
})

const typeEmoji = { '功能测试': '🧩', '性能测试': '⚡', '安全测试': '🔒' }

const groupedTestCases = computed(() => {
  const groups = {}
  for (const tc of testCases.value) {
    const t = tc.test_type || '其他'
    if (!groups[t]) groups[t] = []
    groups[t].push(tc)
  }
  return groups
})

const passRate = computed(() => {
  const total = codeGeneration.value?.unit_tests_count
  const passed = codeGeneration.value?.passed_tests_count
  if (!total) return '—'
  return `${Math.round((passed / total) * 100)}%`
})

// 增量解析 Dev Agent 流式 JSON
const devStreamParsed = computed(() => {
  const text = streamText.value
  const result = { java_code: '', unit_tests: '', implementation_notes: '', currentField: null }
  if (!text) return result

  const fields = ['implementation_notes', 'java_code', 'unit_tests', 'unit_tests_count', 'passed_tests_count']
  for (const field of fields) {
    const key = `"${field}"`
    const idx = text.indexOf(key)
    if (idx === -1) continue

    let start = idx + key.length
    // 跳过展展、蛇形、引号
    while (start < text.length && (text[start] === ' ' || text[start] === ':')) start++
    if (start >= text.length || text[start] !== '"') continue
    start++ // 跳过开头引号

    let value = ''
    let i = start
    let closed = false
    while (i < text.length) {
      if (text[i] === '\\' && i + 1 < text.length) {
        const esc = text[i + 1]
        if (esc === 'n')      value += '\n'
        else if (esc === 't') value += '\t'
        else if (esc === 'r') value += ''
        else                  value += esc
        i += 2
      } else if (text[i] === '"') {
        closed = true
        break
      } else {
        value += text[i]
        i++
      }
    }
    if (field in result) result[field] = value
    if (!closed) result.currentField = field
  }
  return result
})

// ---- 流式解析工具函数 ----
function _parseStreamStr(text, fieldName) {
  const idx = text.indexOf(`"${fieldName}"`)
  if (idx === -1) return { value: '', active: false }
  let start = idx + fieldName.length + 2
  while (start < text.length && (text[start] === ' ' || text[start] === ':')) start++
  if (start >= text.length || text[start] !== '"') return { value: '', active: false }
  start++
  let value = '', i = start, closed = false
  while (i < text.length) {
    if (text[i] === '\\' && i + 1 < text.length) {
      const e = text[i + 1]
      value += e === 'n' ? '\n' : e === 't' ? '\t' : e
      i += 2
    } else if (text[i] === '"') { closed = true; break
    } else { value += text[i++] }
  }
  return { value, active: !closed }
}

function _parseStreamStrArray(text, fieldName) {
  const idx = text.indexOf(`"${fieldName}"`)
  if (idx === -1) return { items: [], active: false }
  let start = idx + fieldName.length + 2
  while (start < text.length && (text[start] === ' ' || text[start] === ':')) start++
  if (start >= text.length || text[start] !== '[') return { items: [], active: false }
  start++
  const items = []
  let i = start, arrayClosed = false
  while (i < text.length) {
    if (text[i] === ']') { arrayClosed = true; break }
    if (text[i] === '"') {
      i++
      let value = '', itemClosed = false
      while (i < text.length) {
        if (text[i] === '\\' && i + 1 < text.length) {
          const e = text[i + 1]
          value += e === 'n' ? '\n' : e === 't' ? '\t' : e
          i += 2
        } else if (text[i] === '"') { itemClosed = true; i++; break
        } else { value += text[i++] }
      }
      if (value.trim()) items.push({ value, active: !itemClosed })
    } else { i++ }
  }
  return { items, active: !arrayClosed }
}

function _parseStreamTestCases(text) {
  const idx = text.indexOf('"test_cases"')
  if (idx === -1) return { names: [], active: false }
  let start = idx + 12
  while (start < text.length && (text[start] === ' ' || text[start] === ':')) start++
  if (start >= text.length || text[start] !== '[') return { names: [], active: false }

  // 用括号深度跟踪真正的 test_cases 数组结束位置，跳过内部 steps[] 等嵌套方括号
  let depth = 0, inStr = false, arrayClosed = false
  for (let i = start; i < text.length; i++) {
    const ch = text[i]
    if (inStr) {
      if (ch === '\\') i++          // 跳过转义字符
      else if (ch === '"') inStr = false
    } else {
      if (ch === '"')  inStr = true
      else if (ch === '[') depth++
      else if (ch === ']') { depth--; if (depth === 0) { arrayClosed = true; break } }
    }
  }

  const arrayText = text.slice(start)
  const names = []
  const re = /"test_name"\s*:\s*"((?:[^"\\]|\\.)*)"/g
  let m
  while ((m = re.exec(arrayText)) !== null) {
    names.push(m[1].replace(/\\n/g, ' ').replace(/\\"/g, '"'))
  }
  return { names, active: !arrayClosed }
}

// PM 流式解析
const pmStreamParsed = computed(() => {
  const t = streamText.value
  const fr  = _parseStreamStrArray(t, 'functional_requirements')
  const nfr = _parseStreamStrArray(t, 'non_functional_requirements')
  const ac  = _parseStreamStrArray(t, 'acceptance_criteria')
  const ec  = _parseStreamStrArray(t, 'edge_cases')
  const sum = _parseStreamStr(t, 'summary')
  let currentSection = null
  for (const [key, val] of [['functional_requirements', fr], ['non_functional_requirements', nfr], ['acceptance_criteria', ac], ['edge_cases', ec]]) {
    if (val.active || val.items.some(i => i.active)) { currentSection = key; break }
  }
  if (!currentSection && sum.active) currentSection = 'summary'
  return { functional_requirements: fr, non_functional_requirements: nfr, acceptance_criteria: ac, edge_cases: ec, summary: sum, currentSection }
})

// QA 流式解析
const qaStreamParsed = computed(() => {
  const t = streamText.value
  const testCases   = _parseStreamTestCases(t)
  const testStrategy  = _parseStreamStr(t, 'test_strategy')
  const coveragePlan  = _parseStreamStr(t, 'coverage_plan')
  let currentSection = null
  if (testCases.active) currentSection = 'test_cases'
  else if (testStrategy.active) currentSection = 'test_strategy'
  else if (coveragePlan.active) currentSection = 'coverage_plan'
  else if (testCases.names.length) currentSection = 'test_cases'
  return { testCases, testStrategy, coveragePlan, currentSection }
})

// 当当前字段切换时自动跳转 Tab
watch(
  () => devStreamParsed.value.currentField,
  (field) => {
    if (field === 'implementation_notes' || field === 'java_code' || field === 'unit_tests') {
      devStreamTab.value = field
    }
  }
)

// 每次收到 chunk时滚动当前活动容器到底部
watch(streamText, () => {
  if (!streaming.value) return
  nextTick(() => {
    // PM / QA 结构化预览區
    if (pmStreamBodyRef.value) pmStreamBodyRef.value.scrollTop = pmStreamBodyRef.value.scrollHeight
    if (qaStreamBodyRef.value) qaStreamBodyRef.value.scrollTop = qaStreamBodyRef.value.scrollHeight
    // Dev 各个容器
    const tabRefMap = {
      implementation_notes: devNotesRef.value,
      java_code: devCodeRef.value,
      unit_tests: devTestsRef.value,
    }
    const el = tabRefMap[devStreamTab.value]
    if (el) el.scrollTop = el.scrollHeight
  })
})

// ---- 工具 ----
function priorityTag(p) {
  const map = { 高: 'danger', P0: 'danger', P1: 'warning', 中: 'warning', 低: 'info', P2: 'info' }
  return map[p] ?? ''
}

function parseNotes(text) {
  if (!text) return []
  // 按换行分割，去掉行首的 "1. " "2. " 等序号，过滤空行
  return text
    .split(/\n/)
    .map(l => l.replace(/^\d+\.\s*/, '').trim())
    .filter(l => l.length > 0)
}

function applySessionResponse(res) {
  status.value = res.status
  if (res.data?.requirement_analysis) requirementAnalysis.value = res.data.requirement_analysis
  if (res.data?.test_cases) {
    const tc = res.data.test_cases
    if (tc.test_cases?.length) testCases.value = tc.test_cases
    if (tc.test_strategy)  testStrategy.value  = tc.test_strategy
    if (tc.coverage_plan)  coveragePlan.value  = tc.coverage_plan
  }
  if (res.data?.code_generation) codeGeneration.value = res.data.code_generation
  if (res.data?.test_execution) testExecution.value = res.data.test_execution
}

async function withLoading(fn, isRefine = false) {
  if (isRefine) refining.value = true
  else loading.value = true
  errorMsg.value = ''
  try {
    const res = await fn()
    applySessionResponse(res)
    return res
  } catch (e) {
    errorMsg.value = e.message
    ElMessage.error(e.message)
  } finally {
    loading.value = false
    refining.value = false
  }
}

async function copyCode(code) {
  await navigator.clipboard.writeText(code)
  ElMessage.success('已复制到剪贴板')
}

// ---- 生命周期 ----
onMounted(async () => {
  // 加载初始会话状态
  loading.value = true
  try {
    const res = await sessionApi.getSession(sessionId)
    status.value = res.status
    rawRequirement.value = res.data?.raw_requirement || ''
    clarifyHistory.value = res.data?.clarify_history || []
    if (res.data?.requirement_analysis) requirementAnalysis.value = res.data.requirement_analysis
    if (res.data?.test_cases) {
      const tc = res.data.test_cases
      if (tc.test_cases?.length) testCases.value = tc.test_cases
      if (tc.test_strategy)  testStrategy.value  = tc.test_strategy
      if (tc.coverage_plan)  coveragePlan.value  = tc.coverage_plan
    }
    if (res.data?.code_generation) codeGeneration.value = res.data.code_generation
    if (res.data?.test_execution) testExecution.value = res.data.test_execution
  } catch (e) {
    errorMsg.value = e.message
  } finally {
    loading.value = false
  }
})

// ---- 操作处理 ----
async function handleClarify() {
  if (!clarifyInput.value.trim()) return
  const msg = clarifyInput.value.trim()
  clarifyInput.value = ''
  clarifyHistory.value.push({ role: 'user', content: msg })

  await withLoading(async () => {
    const res = await sessionApi.clarify(sessionId, msg)
    if (res.question) {
      clarifyHistory.value.push({ role: 'assistant', content: res.question })
    }
    return res
  })
}

// ---- 流式 SSE 请求工具 ----
async function withStreaming(fetchFn, step) {
  streamText.value = ''
  streaming.value = true
  loadingStep.value = step
  devStreamTab.value = 'implementation_notes'  // 每次重新生成从第一个 tab 开始
  errorMsg.value = ''
  try {
    const response = await fetchFn()
    if (!response.ok) {
      const err = await response.json().catch(() => ({ detail: '请求失败' }))
      throw new Error(err.detail || '请求失败')
    }
    const reader = response.body.getReader()
    const decoder = new TextDecoder()
    let buffer = ''

    while (true) {
      const { done, value } = await reader.read()
      if (done) break
      buffer += decoder.decode(value, { stream: true })

      // 按 \n\n 分割完整 SSE 事件
      const parts = buffer.split('\n\n')
      buffer = parts.pop()  // 保留最后不完整的新事件

      for (const part of parts) {
        const line = part.trim()
        if (!line.startsWith('data: ')) continue
        const data = JSON.parse(line.slice(6))
        if (data.type === 'chunk') {
          streamText.value += data.text
          // 滚动由 watch(streamText) 统一处理
        } else if (data.type === 'done') {
          applySessionResponse(data)
        } else if (data.type === 'error') {
          throw new Error(data.message)
        }
      }
    }
  } catch (e) {
    errorMsg.value = e.message
    ElMessage.error(e.message)
  } finally {
    streaming.value = false
    loadingStep.value = null
  }
}

async function handlePmRun() {
  await withStreaming(() => sessionApi.pmStream(sessionId), 1)
}

async function handleQaRun() {
  await withStreaming(() => sessionApi.qaStream(sessionId), 2)
}

async function handleDevRun() {
  await withStreaming(() => sessionApi.devStream(sessionId), 3)
}

async function handlePmRefine() {
  if (!pmFeedback.value.trim()) return
  const fb = pmFeedback.value.trim()
  pmFeedback.value = ''
  await withStreaming(() => sessionApi.pmRefineStream(sessionId, fb), 1)
}

async function handleQaRefine() {
  if (!qaFeedback.value.trim()) return
  const fb = qaFeedback.value.trim()
  qaFeedback.value = ''
  await withStreaming(() => sessionApi.qaRefineStream(sessionId, fb), 2)
}

async function handleDevRefine() {
  if (!devFeedback.value.trim()) return
  const fb = devFeedback.value.trim()
  devFeedback.value = ''
  await withLoading(() => sessionApi.devRefine(sessionId, fb), true)
}

async function handleTestRun() {
  loadingStep.value = 4
  await withLoading(() => sessionApi.testRun(sessionId))
  loadingStep.value = null
}

async function doTestRun() {
  await withLoading(() => sessionApi.testRun(sessionId))
}

async function handleTestFix() {
  loadingStep.value = 3   // 立即导航到 Dev 页
  testExecution.value = null
  await withStreaming(() => sessionApi.testFixStream(sessionId), 3)
}
</script>

<style scoped>
.session-wrap {
  min-height: 100vh;
  background: #f5f7fa;
  padding-bottom: 60px;
}

.top-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 24px;
  background: #fff;
  border-bottom: 1px solid #ebeef5;
  position: sticky;
  top: 0;
  z-index: 100;
}

.session-id {
  font-size: 12px;
  color: #909399;
}

.steps-container {
  background: #fff;
  padding: 24px 40px 16px;
  border-bottom: 1px solid #ebeef5;
}

.content-area {
  max-width: 900px;
  margin: 32px auto;
  padding: 0 20px;
}

.step-card {
  border-radius: 12px;
  border: 1px solid #ebeef5;
}

.card-header {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 16px;
  font-weight: 600;
}

/* AI 思考中卡片（PM / QA）*/
.thinking-card {
  border: 1px solid #e0eaff;
  border-radius: 12px;
  overflow: hidden;
  background: #f6f8ff;
}

/* Dev Agent 流式代码卡片 */
.dev-stream-card {
  border: 1px solid #e0eaff;
  border-radius: 12px;
  overflow: hidden;
  background: #fff;
}

.dev-stream-card .thinking-header {
  border-radius: 0;
}

.dev-stream-tabs {
  padding: 0 12px 12px;
}

.dev-stream-notes {
  padding: 14px 16px;
  font-size: 13px;
  line-height: 1.8;
  color: #4a5568;
  white-space: pre-wrap;
  min-height: 80px;
  max-height: 260px;
  overflow-y: auto;
  font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Hiragino Sans GB', sans-serif;
}

/* 代码块里的打字光标 */
.dev-cursor {
  color: #67c23a;
  font-weight: 100;
}

/* 流式输出时的代码 pre：固定高度 + 纵向滚动，供 scrollTop 控制 */
.dev-stream-code {
  max-height: 480px;
  overflow-y: auto;
  overflow-x: auto;
}

.thinking-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 18px;
  background: linear-gradient(90deg, #eef2ff 0%, #f6f8ff 100%);
  border-bottom: 1px solid #e0eaff;
  font-size: 13px;
}

.thinking-title {
  font-weight: 600;
  color: #4f6ef7;
  flex: 1;
}

.thinking-count {
  font-size: 11px;
  color: #a0aec0;
  font-variant-numeric: tabular-nums;
}

/* 三点动画 */
.thinking-dots {
  display: inline-flex;
  gap: 4px;
  align-items: center;
}
.thinking-dots span {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #4f6ef7;
  animation: dot-bounce 1.2s infinite ease-in-out;
}
.thinking-dots span:nth-child(2) { animation-delay: 0.2s; }
.thinking-dots span:nth-child(3) { animation-delay: 0.4s; }
@keyframes dot-bounce {
  0%, 80%, 100% { transform: scale(0.6); opacity: 0.4; }
  40% { transform: scale(1); opacity: 1; }
}

.thinking-body {
  padding: 16px 18px;
  font-size: 13px;
  line-height: 1.8;
  color: #4a5568;
  white-space: pre-wrap;
  word-break: break-all;
  max-height: 380px;
  overflow-y: auto;
  font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Hiragino Sans GB', sans-serif;
}

/* PM / QA 结构化流式预览 */
.stream-sections-body {
  max-height: 420px;
  overflow-y: auto;
  padding: 6px 4px;
}
.stream-section {
  margin: 0 8px 10px;
  padding: 10px 14px;
  border-radius: 8px;
  border-left: 3px solid transparent;
  background: #f8f9ff;
  transition: border-color 0.2s, background 0.2s;
}
.stream-section--active {
  border-left-color: #4f6ef7;
  background: #eef1ff;
}
.stream-section-title {
  font-size: 12px;
  font-weight: 600;
  color: #4f6ef7;
  margin-bottom: 6px;
  letter-spacing: 0.03em;
}
.stream-list {
  margin: 0;
  padding-left: 18px;
  list-style: disc;
}
.stream-list li {
  font-size: 13px;
  line-height: 1.7;
  color: #374151;
  margin-bottom: 2px;
  word-break: break-word;
}
.stream-text-content {
  font-size: 13px;
  line-height: 1.8;
  color: #374151;
  margin: 0;
  word-break: break-word;
  white-space: pre-wrap;
}
.stream-waiting {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  color: #9ca3af;
  font-size: 13px;
}
/* QA 测试用例条目 */
.qa-stream-cases {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.qa-stream-case-item {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: #374151;
  padding: 3px 0;
}
.qa-case-badge {
  display: inline-block;
  background: #dbeafe;
  color: #1d4ed8;
  border-radius: 4px;
  padding: 1px 6px;
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
  flex-shrink: 0;
}
.qa-stream-case-writing {
  display: flex;
  align-items: center;
  gap: 6px;
  color: #9ca3af;
  font-size: 13px;
  padding: 3px 0;
}

/* 光标闪烁 */
.cursor {
  display: inline-block;
  width: 2px;
  color: #4f6ef7;
  animation: blink 0.8s step-end infinite;
}
@keyframes blink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0; }
}

/* 加载态 */
.loading-area {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 40px 0;
  justify-content: center;
  color: #909399;
  font-size: 14px;
}

.spinning {
  animation: spin 1s linear infinite;
  font-size: 24px;
  color: #409eff;
}
@keyframes spin { from { transform: rotate(0deg) } to { transform: rotate(360deg) } }

/* 需求块 */
.req-block {
  background: #f8f9fa;
  border-radius: 8px;
  padding: 16px;
  margin-bottom: 16px;
}

.block-label {
  font-size: 13px;
  font-weight: 600;
  color: #606266;
  margin-bottom: 8px;
}

.req-text {
  font-size: 14px;
  color: #303133;
  white-space: pre-wrap;
  line-height: 1.7;
}

/* 对话历史 */
.chat-history {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 16px 0;
}

.chat-msg {
  display: flex;
  flex-direction: column;
  max-width: 80%;
}

.chat-msg.assistant {
  align-self: flex-start;
  align-items: flex-start;
}

.chat-msg.user {
  align-self: flex-end;
  align-items: flex-end;
}

.chat-bubble {
  padding: 10px 14px;
  border-radius: 12px;
  font-size: 14px;
  line-height: 1.6;
  white-space: pre-wrap;
}

.chat-msg.assistant .chat-bubble {
  background: #ecf5ff;
  color: #303133;
  border-bottom-left-radius: 4px;
}

.chat-msg.user .chat-bubble {
  background: #409eff;
  color: #fff;
  border-bottom-right-radius: 4px;
}

.chat-role {
  font-size: 12px;
  color: #909399;
  margin-top: 4px;
}

/* 结果区块 */
.result-section {
  margin-bottom: 20px;
}

.section-title {
  font-size: 14px;
  font-weight: 600;
  color: #303133;
  margin-bottom: 8px;
}

.section-text {
  font-size: 14px;
  color: #606266;
  line-height: 1.7;
  margin: 0;
}

.feature-list {
  padding-left: 20px;
  margin: 0;
  font-size: 14px;
  color: #606266;
  line-height: 2;
}

/* 测试用例 */
.test-group {
  margin-bottom: 24px;
}

.test-group-title {
  font-size: 15px;
  font-weight: 600;
  color: #303133;
  margin-bottom: 12px;
}

.test-table :deep(.cell) {
  white-space: pre-wrap;
  line-height: 1.6;
}

.step-list {
  padding-left: 16px;
  margin: 0;
  font-size: 13px;
  line-height: 1.8;
}

/* 统计卡片 */
.stat-row {
  display: flex;
  gap: 16px;
  margin-bottom: 24px;
}

.stat-card {
  flex: 1;
  background: #f8f9fa;
  border-radius: 10px;
  padding: 16px;
  text-align: center;
}

.stat-num {
  font-size: 28px;
  font-weight: 700;
  color: #409eff;
}

.stat-label {
  font-size: 12px;
  color: #909399;
  margin-top: 4px;
}

/* 代码块 */
.code-tabs {
  margin-top: 16px;
}

.code-block-wrap {
  position: relative;
  background: #1e1e2e;
  border-radius: 8px;
  padding: 40px 16px 16px;
  overflow: auto;
}

.code-lang-badge {
  position: absolute;
  top: 10px;
  left: 16px;
  font-size: 11px;
  color: #888;
  text-transform: uppercase;
  letter-spacing: 1px;
}

.copy-btn {
  position: absolute;
  top: 6px;
  right: 12px;
  color: #888 !important;
}

.code-block {
  margin: 0;
  font-family: 'Fira Code', 'JetBrains Mono', Consolas, monospace;
  font-size: 13px;
  line-height: 1.7;
  color: #cdd6f4;
  white-space: pre;
  overflow-x: auto;
}

/* 反馈区 */
.qa-meta-row {
  display: flex;
  gap: 24px;
  flex-wrap: wrap;
  margin: 4px 0 8px;
}
.qa-meta-block {
  flex: 1;
  min-width: 220px;
}
.qa-meta-text {
  margin: 4px 0 0;
  font-size: 13px;
  line-height: 1.7;
  color: #374151;
  white-space: pre-wrap;
  word-break: break-word;
}

.feedback-area {
  margin-top: 8px;
}

.btn-row {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 12px;
}
</style>
