<template>
  <div class="rag-lab-page">
    <div class="page-header">
      <h1 class="page-title">RAG 实验室</h1>
      <p class="page-desc">测试检索增强生成效果，查看检索结果和 AI 响应。</p>
    </div>

    <el-row :gutter="24">
      <el-col :xs="24" :sm="24" :md="10" :lg="10">
        <el-card shadow="hover" class="input-card">
          <template #header>
            <div class="card-header">
              <div class="header-left">
                <div class="icon-wrapper">
                  <el-icon><Edit /></el-icon>
                </div>
                <span class="header-title">调试输入</span>
              </div>
              <el-switch
                v-model="flowTestMode"
                active-text="完整流程测试"
                inactive-text="RAG 测试"
                @change="handleModeChange"
              />
            </div>
          </template>
          <el-form label-position="top">
            <el-form-item label="查询 Query">
              <el-input
                v-model="query"
                type="textarea"
                :rows="4"
                placeholder="输入测试问题..."
              />
            </el-form-item>
            <el-form-item label="知识库范围" v-if="!flowTestMode">
              <el-select
                v-model="kbIds"
                multiple
                placeholder="请选择知识库"
                style="width: 100%"
                :loading="kbLoading"
                :teleported="true"
                :popper-options="{ modifiers: [{ name: 'flip', enabled: true }, { name: 'preventOverflow', enabled: true }] }"
              >
                <el-option
                  v-for="kb in knowledgeBases"
                  :key="kb.id"
                  :label="`${kb.name} (${kb.documentCount}个文档)`"
                  :value="kb.id"
                />
              </el-select>
            </el-form-item>
            <el-form-item label="LLM 模型" v-if="!flowTestMode">
              <LLMSelector
                v-model="llmProvider"
                :providers="llmProviders"
                :loading="llmLoading"
                :current-provider="currentLLMProvider"
                placeholder="使用默认配置"
                clearable
                @change="handleLLMChange"
              />
            </el-form-item>

            <template v-if="flowTestMode">
              <el-divider content-position="left">流程配置</el-divider>
              <div class="flow-config">
                <div class="config-item">
                  <span class="config-label">意图识别</span>
                  <el-switch v-model="flowConfig.enable_intent" />
                </div>
                <div class="config-item">
                  <span class="config-label">话术流程</span>
                  <el-switch v-model="flowConfig.enable_flow" />
                </div>
                <div class="config-item">
                  <span class="config-label">RAG 检索</span>
                  <el-switch v-model="flowConfig.enable_rag" />
                </div>
                <div class="config-item">
                  <span class="config-label">输出护栏</span>
                  <el-switch v-model="flowConfig.enable_guardrail" />
                </div>
                <div class="config-item">
                  <span class="config-label">上下文记忆</span>
                  <el-switch v-model="flowConfig.enable_memory" />
                </div>
              </div>
            </template>

            <template v-if="!flowTestMode">
              <el-form-item label="参数配置">
                <div class="param-item">
                  <span class="label">Top-K</span>
                  <el-input-number v-model="topK" :min="1" :max="10" />
                </div>
                <div class="param-item">
                  <span class="label">Score Threshold</span>
                  <el-slider
                    v-model="scoreThreshold"
                    :min="0"
                    :max="1"
                    :step="0.1"
                    show-input
                  />
                </div>
                <div class="param-item">
                  <span class="label">生成 AI 回复</span>
                  <el-switch v-model="generateResponse" />
                </div>
                <div class="param-item" v-if="generateResponse">
                  <span class="label">流式输出</span>
                  <el-switch v-model="streamOutput" />
                </div>
              </el-form-item>
            </template>

            <el-button 
              type="primary" 
              block 
              @click="handleRun" 
              :loading="loading || streaming"
            >
              {{ flowTestMode ? '执行流程测试' : (streaming ? '生成中...' : '运行实验') }}
            </el-button>
            <el-button 
              v-if="streaming" 
              type="danger" 
              block 
              @click="handleStopStream"
              style="margin-top: 10px;"
            >
              停止生成
            </el-button>
          </el-form>
        </el-card>
      </el-col>

      <el-col :xs="24" :sm="24" :md="14" :lg="14">
        <template v-if="flowTestMode">
          <el-card shadow="hover" class="result-card" v-loading="loading">
            <template #header>
              <div class="card-header">
                <div class="header-left">
                  <div class="icon-wrapper success">
                    <el-icon><Share /></el-icon>
                  </div>
                  <span class="header-title">执行流程 (12步)</span>
                </div>
                <div class="header-right" v-if="flowTestResult">
                  <el-tag :type="getStatusType(flowTestResult.status)" size="small">
                    {{ flowTestResult.status }}
                  </el-tag>
                  <span class="duration">{{ flowTestResult.total_duration_ms }}ms</span>
                </div>
              </div>
            </template>

            <div v-if="!flowTestResult" class="placeholder-text">
              切换到"完整流程测试"模式，输入测试消息后点击执行
            </div>

            <div v-else class="flow-result">
              <el-timeline>
                <el-timeline-item
                  v-for="step in flowTestResult.steps"
                  :key="step.step"
                  :type="getStepStatusType(step.status)"
                  :hollow="step.status === 'skipped'"
                  size="large"
                >
                  <el-card shadow="never" class="step-card" @click="toggleStepDetail(step.step)">
                    <div class="step-header">
                      <div class="step-info">
                        <span class="step-number">Step {{ step.step }}</span>
                        <span class="step-name">{{ getStepName(step.name) }}</span>
                      </div>
                      <div class="step-meta">
                        <el-tag :type="getStepStatusType(step.status)" size="small" effect="plain">
                          {{ step.status }}
                        </el-tag>
                        <span class="step-duration">{{ step.duration_ms }}ms</span>
                      </div>
                    </div>
                    <div v-if="expandedSteps.includes(step.step)" class="step-detail">
                      <el-divider content-position="left">输入</el-divider>
                      <pre class="code-block"><code>{{ JSON.stringify(step.input, null, 2) }}</code></pre>
                      <el-divider content-position="left">输出</el-divider>
                      <pre class="code-block"><code>{{ JSON.stringify(step.output, null, 2) }}</code></pre>
                      <template v-if="step.error">
                        <el-divider content-position="left">错误</el-divider>
                        <el-alert type="error" :closable="false">{{ step.error }}</el-alert>
                      </template>
                    </div>
                  </el-card>
                </el-timeline-item>
              </el-timeline>

              <el-divider content-position="left" v-if="flowTestResult.final_response">最终响应</el-divider>
              <div v-if="flowTestResult.final_response" class="final-response">
                <div class="response-content">{{ flowTestResult.final_response.reply }}</div>
                <div class="response-meta">
                  <span v-if="flowTestResult.final_response.confidence">
                    置信度: {{ (flowTestResult.final_response.confidence * 100).toFixed(1) }}%
                  </span>
                  <el-tag v-if="flowTestResult.final_response.should_transfer" type="warning" size="small">
                    需转人工
                  </el-tag>
                </div>
              </div>
            </div>
          </el-card>
        </template>

        <template v-else>
          <el-tabs v-model="activeTab" type="border-card" class="result-tabs">
            <el-tab-pane label="召回片段" name="retrieval">
              <div v-if="retrievalResults.length === 0" class="placeholder-text">
                暂无实验数据
              </div>
              <div v-else class="result-list">
                <el-card
                  v-for="(item, index) in retrievalResults"
                  :key="index"
                  class="result-card"
                  shadow="never"
                >
                  <div class="result-header">
                    <el-tag size="small" type="primary">Score: {{ item.score.toFixed(4) }}</el-tag>
                    <span class="source">来源: {{ item.source }}</span>
                  </div>
                  <div class="result-content">{{ item.content }}</div>
                </el-card>
              </div>
            </el-tab-pane>
            <el-tab-pane label="最终 Prompt" name="prompt">
              <div v-if="!finalPrompt" class="placeholder-text">
                等待实验运行...
              </div>
              <div v-else class="prompt-view">
                <pre><code>{{ finalPrompt }}</code></pre>
              </div>
            </el-tab-pane>
            <el-tab-pane label="AI 回复" name="ai-response" v-if="generateResponse">
              <StreamOutput
                v-if="streamOutput"
                :content="streamContent"
                :is-streaming="streaming"
                :error="streamError"
              />
              <AIResponseViewer
                v-else
                :response="aiResponse"
              />
            </el-tab-pane>
            <el-tab-pane label="诊断信息" name="diagnostics">
              <div v-if="!diagnostics" class="placeholder-text">
                等待实验运行...
              </div>
              <div v-else class="diagnostics-view">
                <pre><code>{{ JSON.stringify(diagnostics, null, 2) }}</code></pre>
              </div>
            </el-tab-pane>
          </el-tabs>
        </template>
      </el-col>
    </el-row>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { Edit, Share } from '@element-plus/icons-vue'
import { runRagExperiment, createSSEConnection, type AIResponse, type RetrievalResult } from '@/api/rag'
import { getLLMProviders, getLLMConfig, type LLMProviderInfo } from '@/api/llm'
import { listKnowledgeBases } from '@/api/kb'
import { executeFlowTest, type FlowExecutionResponse, type FlowExecutionStep } from '@/api/flow-test'
import { useRagLabStore } from '@/stores/ragLab'
import { storeToRefs } from 'pinia'
import AIResponseViewer from '@/components/rag/AIResponseViewer.vue'
import StreamOutput from '@/components/rag/StreamOutput.vue'
import LLMSelector from '@/components/rag/LLMSelector.vue'

interface KnowledgeBase {
  id: string
  name: string
  documentCount: number
}

const ragLabStore = useRagLabStore()
const { 
  query, 
  kbIds, 
  llmProvider, 
  topK, 
  scoreThreshold, 
  generateResponse, 
  streamOutput 
} = storeToRefs(ragLabStore)

const loading = ref(false)
const kbLoading = ref(false)
const llmLoading = ref(false)
const streaming = ref(false)
const activeTab = ref('retrieval')
const knowledgeBases = ref<KnowledgeBase[]>([])
const llmProviders = ref<LLMProviderInfo[]>([])
const currentLLMProvider = ref('')

const retrievalResults = ref<RetrievalResult[]>([])
const finalPrompt = ref('')
const aiResponse = ref<AIResponse | null>(null)
const diagnostics = ref<any>(null)
const streamContent = ref('')
const streamError = ref<string | null>(null)

const totalLatencyMs = ref(0)

const flowTestMode = ref(false)
const flowTestResult = ref<FlowExecutionResponse | null>(null)
const expandedSteps = ref<number[]>([])

const flowConfig = reactive({
  enable_intent: true,
  enable_flow: true,
  enable_rag: true,
  enable_guardrail: true,
  enable_memory: true
})

let abortStream: (() => void) | null = null

const stepNameMap: Record<string, string> = {
  'InputScanner': '输入扫描',
  'FlowEngine': '流程引擎',
  'IntentRouter': '意图路由',
  'QueryRewriter': '查询重写',
  'MultiKBRetrieval': '多知识库检索',
  'ResultRanker': '结果排序',
  'PromptBuilder': 'Prompt 构建',
  'LLMGenerate': 'LLM 生成',
  'OutputFilter': '输出过滤',
  'Confidence': '置信度计算',
  'Memory': '记忆存储',
  'Response': '响应返回'
}

const getStepName = (name: string) => {
  return stepNameMap[name] || name
}

const getStatusType = (status: string) => {
  switch (status) {
    case 'success': return 'success'
    case 'failed': return 'danger'
    case 'partial': return 'warning'
    default: return 'info'
  }
}

const getStepStatusType = (status: string) => {
  switch (status) {
    case 'success': return 'success'
    case 'failed': return 'danger'
    case 'skipped': return 'info'
    default: return 'warning'
  }
}

const toggleStepDetail = (step: number) => {
  const index = expandedSteps.value.indexOf(step)
  if (index > -1) {
    expandedSteps.value.splice(index, 1)
  } else {
    expandedSteps.value.push(step)
  }
}

const handleModeChange = () => {
  flowTestResult.value = null
  expandedSteps.value = []
  clearResults()
}

const fetchKnowledgeBases = async () => {
  kbLoading.value = true
  try {
    const res: any = await listKnowledgeBases()
    knowledgeBases.value = res.data || []
  } catch (error) {
    console.error('Failed to fetch knowledge bases:', error)
  } finally {
    kbLoading.value = false
  }
}

const fetchLLMProviders = async () => {
  llmLoading.value = true
  try {
    const [providersRes, configRes]: [any, any] = await Promise.all([
      getLLMProviders(),
      getLLMConfig()
    ])
    llmProviders.value = providersRes?.providers || []
    currentLLMProvider.value = configRes?.provider || ''
  } catch (error) {
    console.error('Failed to fetch LLM providers:', error)
  } finally {
    llmLoading.value = false
  }
}

const handleLLMChange = (provider: LLMProviderInfo | undefined) => {
  llmProvider.value = provider?.name || ''
}

const handleRun = async () => {
  if (!query.value.trim()) {
    ElMessage.warning('请输入查询 Query')
    return
  }

  if (flowTestMode.value) {
    await runFlowTest()
  } else {
    clearResults()
    if (streamOutput.value && generateResponse.value) {
      await runStreamExperiment()
    } else {
      await runNormalExperiment()
    }
  }
}

const runFlowTest = async () => {
  loading.value = true
  flowTestResult.value = null
  expandedSteps.value = []
  
  try {
    const result = await executeFlowTest({
      message: query.value,
      enable_flow: flowConfig.enable_flow,
      enable_intent: flowConfig.enable_intent,
      enable_rag: flowConfig.enable_rag,
      enable_guardrail: flowConfig.enable_guardrail,
      enable_memory: flowConfig.enable_memory
    })
    
    flowTestResult.value = result
    ElMessage.success('流程测试完成')
  } catch (err: any) {
    console.error(err)
    ElMessage.error(err?.message || '流程测试失败')
  } finally {
    loading.value = false
  }
}

const runNormalExperiment = async () => {
  loading.value = true
  try {
    const res: any = await runRagExperiment({
      query: query.value,
      kb_ids: kbIds.value,
      top_k: topK.value,
      score_threshold: scoreThreshold.value,
      llm_provider: llmProvider.value || undefined,
      generate_response: generateResponse.value
    })
    
    retrievalResults.value = res.retrieval_results || res.retrievalResults || []
    finalPrompt.value = res.final_prompt || res.finalPrompt || ''
    aiResponse.value = res.ai_response || res.aiResponse || null
    diagnostics.value = res.diagnostics || null
    totalLatencyMs.value = res.total_latency_ms || res.totalLatencyMs || 0
    
    if (generateResponse.value) {
      activeTab.value = 'ai-response'
    } else {
      activeTab.value = 'retrieval'
    }
    
    ElMessage.success('实验运行成功')
  } catch (err: any) {
    console.error(err)
    ElMessage.error(err?.message || '实验运行失败')
  } finally {
    loading.value = false
  }
}

const runStreamExperiment = async () => {
  streaming.value = true
  streamContent.value = ''
  streamError.value = null
  activeTab.value = 'ai-response'
  
  abortStream = createSSEConnection(
    '/admin/rag/experiments/stream',
    {
      query: query.value,
      kb_ids: kbIds.value,
      top_k: topK.value,
      score_threshold: scoreThreshold.value,
      llm_provider: llmProvider.value || undefined,
      generate_response: true
    },
    (data: string) => {
      try {
        const parsed = JSON.parse(data)
        
        if (parsed.type === 'content') {
          streamContent.value += parsed.content || ''
        } else if (parsed.type === 'retrieval') {
          retrievalResults.value = parsed.results || []
        } else if (parsed.type === 'prompt') {
          finalPrompt.value = parsed.prompt || ''
        } else if (parsed.type === 'complete') {
          aiResponse.value = {
            content: streamContent.value,
            prompt_tokens: parsed.prompt_tokens,
            completion_tokens: parsed.completion_tokens,
            total_tokens: parsed.total_tokens,
            latency_ms: parsed.latency_ms,
            model: parsed.model
          }
          totalLatencyMs.value = parsed.total_latency_ms || 0
          streaming.value = false
          ElMessage.success('生成完成')
        } else if (parsed.type === 'error') {
          streamError.value = parsed.message || '流式输出错误'
          streaming.value = false
          ElMessage.error(streamError.value || '未知错误')
        }
      } catch {
        streamContent.value += data
      }
    },
    (error: Error) => {
      streaming.value = false
      streamError.value = error.message
      ElMessage.error(error.message)
    },
    () => {
      streaming.value = false
    }
  )
}

const handleStopStream = () => {
  if (abortStream) {
    abortStream()
    abortStream = null
  }
  streaming.value = false
  ElMessage.info('已停止生成')
}

const clearResults = () => {
  retrievalResults.value = []
  finalPrompt.value = ''
  aiResponse.value = null
  diagnostics.value = null
  streamContent.value = ''
  streamError.value = null
  totalLatencyMs.value = 0
}

onMounted(() => {
  fetchKnowledgeBases()
  fetchLLMProviders()
})
</script>

<style scoped>
.rag-lab-page {
  padding: 24px;
  min-height: calc(100vh - 60px);
}

.page-header {
  margin-bottom: 24px;
}

.page-title {
  margin: 0 0 8px 0;
  font-size: 24px;
  font-weight: 700;
  color: var(--text-primary);
  letter-spacing: -0.5px;
}

.page-desc {
  margin: 0;
  font-size: 14px;
  color: var(--text-secondary);
  line-height: 1.6;
}

.input-card {
  animation: fadeInUp 0.5s ease-out;
}

@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0;
}

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

.icon-wrapper {
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--primary-lighter);
  border-radius: 10px;
  color: var(--primary-color);
  font-size: 18px;
}

.icon-wrapper.success {
  background-color: #D1FAE5;
  color: #059669;
}

.header-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--text-primary);
}

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

.duration {
  font-size: 13px;
  color: var(--text-secondary);
}

.flow-config {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  margin-bottom: 16px;
}

.config-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  background-color: var(--bg-tertiary);
  border-radius: 8px;
}

.config-label {
  font-size: 13px;
  color: var(--text-secondary);
}

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

.param-item .label {
  width: 140px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-secondary);
  flex-shrink: 0;
}

.param-item :deep(.el-slider) {
  flex: 1;
}

.result-tabs {
  animation: fadeInUp 0.6s ease-out;
}

.result-tabs :deep(.el-tabs__header) {
  border-radius: 12px 12px 0 0;
}

.placeholder-text {
  color: var(--text-tertiary);
  text-align: center;
  padding: 60px 20px;
  font-size: 14px;
}

.result-list {
  max-height: 600px;
  overflow-y: auto;
  padding-right: 8px;
}

.result-card {
  margin-bottom: 16px;
  border: 1px solid var(--border-color);
}

.result-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
}

.source {
  font-size: 12px;
  color: var(--text-tertiary);
}

.result-content {
  font-size: 14px;
  line-height: 1.7;
  color: var(--text-primary);
}

.prompt-view,
.diagnostics-view {
  background-color: var(--bg-tertiary);
  padding: 16px;
  border-radius: 10px;
  max-height: 600px;
  overflow-y: auto;
}

.prompt-view pre,
.diagnostics-view pre {
  margin: 0;
  white-space: pre-wrap;
  word-wrap: break-word;
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1.6;
  color: var(--text-primary);
}

.flow-result {
  max-height: 700px;
  overflow-y: auto;
}

.step-card {
  cursor: pointer;
  transition: all 0.2s ease;
}

.step-card:hover {
  background-color: var(--bg-tertiary);
}

.step-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.step-info {
  display: flex;
  align-items: center;
  gap: 12px;
}

.step-number {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-tertiary);
  background-color: var(--bg-tertiary);
  padding: 2px 8px;
  border-radius: 4px;
}

.step-name {
  font-size: 14px;
  font-weight: 500;
  color: var(--text-primary);
}

.step-meta {
  display: flex;
  align-items: center;
  gap: 12px;
}

.step-duration {
  font-size: 12px;
  color: var(--text-tertiary);
}

.step-detail {
  margin-top: 16px;
}

.code-block {
  background-color: var(--bg-tertiary);
  padding: 12px;
  border-radius: 8px;
  font-size: 12px;
  overflow-x: auto;
  margin: 0;
}

.code-block code {
  font-family: var(--font-mono);
  white-space: pre-wrap;
  word-wrap: break-word;
}

.final-response {
  background-color: var(--bg-tertiary);
  padding: 16px;
  border-radius: 12px;
}

.response-content {
  font-size: 14px;
  line-height: 1.7;
  color: var(--text-primary);
  margin-bottom: 12px;
}

.response-meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 13px;
  color: var(--text-secondary);
}

@media (max-width: 768px) {
  .rag-lab-page {
    padding: 16px;
  }

  .page-title {
    font-size: 20px;
  }

  .param-item {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }

  .param-item .label {
    width: 100%;
  }

  .flow-config {
    grid-template-columns: 1fr;
  }
}
</style>
