<template>
  <div class="chat-test-page">
    <!-- 左侧：工作流配置面板 -->
    <div class="left-panel">
      <el-card shadow="never" class="config-card">
        <div slot="header" class="card-header">
          <span><i class="el-icon-setting"></i> 测试配置</span>
          <el-button type="success" size="mini" icon="el-icon-thumb" @click="runE2eOnce" :loading="e2eLoading" style="margin-left:8px">一键E2E</el-button>
        </div>

        <el-form label-width="80px" size="small">
          <el-form-item label="选择模板">
            <el-select v-model="selectedTemplateId" placeholder="选择工作流模板" filterable
              style="width:100%" @change="onTemplateChange">
              <el-option v-for="t in templates" :key="t.id" :label="t.templateName || t.promptName"
                :value="t.id" />
            </el-select>
          </el-form-item>
          <el-form-item label="E2E输入">
            <el-input type="textarea" v-model="e2eUserInputs" :rows="3" placeholder="每行一条，一键E2E依次喂入" />
          </el-form-item>
          <el-form-item label="模拟日期">
            <el-date-picker v-model="simulateDate" type="datetime" value-format="yyyy-MM-dd HH:mm:ss"
              placeholder="选择模拟时间" style="width:100%" />
          </el-form-item>
          <el-form-item label="测试模式">
            <el-radio-group v-model="testMode">
              <el-radio label="full">全流程</el-radio>
              <el-radio label="step">逐节点</el-radio>
            </el-radio-group>
          </el-form-item>
        </el-form>

        <!-- 工作流节点预览 -->
        <div v-if="templateNodes.length > 0" class="node-preview">
          <div class="section-title">节点流程（{{ templateNodes.length }}个）</div>
          <el-steps direction="vertical" :active="currentNodeIndex" finish-status="success" process-status="process">
            <el-step v-for="(node, idx) in templateNodes" :key="node.nodeCode"
              :title="node.nodeName"
              :description="getNodeTypeText(node.nodeType)">
              <template slot="icon">
                <i :class="getNodeIcon(node.nodeType)" :style="{color: getNodeColor(node.nodeType)}"></i>
              </template>
            </el-step>
          </el-steps>
        </div>
      </el-card>
    </div>

    <!-- 中间：聊天区域 -->
    <div class="center-panel">
      <div class="chat-container">
        <div class="chat-header">
          <span><i class="el-icon-chat-dot-round"></i> 模拟聊天测试</span>
          <div>
            <el-tag v-if="currentNode" size="small" :type="getNodeTagType(currentNode.nodeType)">
              当前节点: {{ currentNode.nodeName }}
            </el-tag>
          </div>
        </div>

        <div class="chat-messages" ref="chatMessages">
          <div v-if="messages.length === 0" class="chat-empty">
            <i class="el-icon-chat-line-square"></i>
            <p>选择工作流模板后，输入客户消息开始对话测试</p>
          </div>

          <div v-for="(msg, idx) in messages" :key="idx"
            :class="['message-row', msg.role === 'customer' ? 'message-right' : 'message-left']">
            <div class="message-bubble" :class="msg.role">
              <div class="message-meta">
                <span class="message-sender">{{ msg.role === 'customer' ? '客户' : 'AI' }}</span>
                <span class="message-time">{{ msg.time }}</span>
                <el-tag v-if="msg.nodeName" size="mini" type="info" class="message-node-tag">
                  {{ msg.nodeName }}
                </el-tag>
              </div>
              <div class="message-content">{{ msg.content }}</div>
              <div v-if="msg.score" class="message-score">
                <span class="score-label">质量评分:</span>
                <el-rate v-model="msg.score" disabled :max="5" show-score text-color="#ff9900" size="small" />
              </div>
            </div>
          </div>

          <div v-if="loading" class="message-row message-left">
            <div class="message-bubble ai typing">
              <span>AI正在生成回复...</span>
            </div>
          </div>
        </div>

        <div class="chat-input-area">
          <el-input v-model="inputMsg" type="textarea" :rows="2"
            placeholder="输入客户消息，模拟对话..."
            :disabled="!selectedTemplateId || loading"
            @keyup.enter.native="sendMessage" />
          <div class="chat-actions">
            <el-button type="primary" size="small" @click="sendMessage"
              :loading="loading" :disabled="!selectedTemplateId || !inputMsg.trim()">
              <i class="el-icon-position"></i> 发送
            </el-button>
            <el-button size="small" @click="resetChat" :disabled="loading">
              <i class="el-icon-refresh"></i> 重置
            </el-button>
          </div>
        </div>
      </div>
    </div>

    <!-- 右侧：节点执行详情 -->
    <div class="right-panel">
      <el-card shadow="never" class="detail-card">
        <div slot="header" class="card-header">
          <span><i class="el-icon-document"></i> 节点执行日志</span>
          <el-button size="mini" type="text" @click="nodeLogs = []">清空</el-button>
        </div>

        <div v-if="nodeLogs.length === 0" class="log-empty">
          <i class="el-icon-info"></i>
          <p>暂无执行日志，发送消息后将在此展示每个节点的执行详情</p>
        </div>

        <el-timeline v-if="nodeLogs.length > 0">
          <el-timeline-item v-for="(log, idx) in nodeLogs" :key="idx"
            :timestamp="log.time" :type="log.error ? 'danger' : 'success'" placement="top">
            <el-card shadow="hover" class="log-card">
              <div class="log-header">
                <el-tag size="mini" :type="getNodeTagType(log.nodeType)">
                  {{ getNodeTypeText(log.nodeType) }}
                </el-tag>
                <span class="log-node-name">{{ log.nodeName }}</span>
                <span v-if="log.duration" class="log-duration">{{ log.duration }}ms</span>
              </div>
              <div v-if="log.input" class="log-section">
                <div class="log-label">接收:</div>
                <div class="log-content">{{ log.input }}</div>
              </div>
              <div v-if="log.output" class="log-section">
                <div class="log-label">输出:</div>
                <div class="log-content output">{{ log.output }}</div>
              </div>
              <div v-if="log.error" class="log-error">{{ log.error }}</div>
            </el-card>
          </el-timeline-item>
        </el-timeline>
      </el-card>
    </div>
  </div>
</template>

<script>
import { simulateChat, listAllTemplates, getTemplateWithNodes } from '@/api/workflow/lobster'
import { runE2e } from '@/api/workflow/lobster-e2e'

export default {
  name: 'ChatTest',
  data() {
    return {
      templates: [],
      selectedTemplateId: null,
      templateNodes: [],
      testMode: 'step',
      simulateDate: null,
      currentNodeIndex: 0,
      currentNode: null,
      inputMsg: '',
      messages: [],
      nodeLogs: [],
      loading: false,
      e2eLoading: false,
      e2eUserInputs: ''
    }
  },
  created() {
    this.loadTemplates()
    this.simulateDate = this.formatDate(new Date())
  },
  methods: {
    async runE2eOnce() {
      if (!this.selectedTemplateId) { this.$message.warning('请先选择模板'); return }
      const inputs = (this.e2eUserInputs || '').split('\n').map(x => x.trim()).filter(x => x)
      if (inputs.length === 0) { this.$message.warning('请输入至少一条用户消息'); return }
      this.e2eLoading = true
      try {
        const res = await runE2e({
          templateId: this.selectedTemplateId,
          userInputs: inputs,
          testContactId: -1
        })
        const r = res.data || res
        this.$notify({
          title: 'E2E 完成',
          message: `总分 ${r.totalScore?.toFixed?.(1) || '-'} | 通过 ${r.passedNodeCnt || 0}/${r.totalNodeCnt || 0} | 进化建议 ${r.evolutionCount || 0}`,
          type: r.status === 'SUCCESS' ? 'success' : 'error',
          duration: 6000
        })
        // 将 nodeTraces 灌进 messages 区
        if (r.nodeTraces) {
          this.messages = []
          r.nodeTraces.forEach(t => {
            if (t.userInput) this.messages.push({ role: 'user', text: t.userInput })
            if (t.aiOutput) this.messages.push({ role: 'ai', text: t.aiOutput, score: t.score, node: t.nodeCode })
          })
        }
      } catch (e) {
        this.$message.error('E2E 失败：' + (e.message || e))
      } finally {
        this.e2eLoading = false
      }
    },
    async loadTemplates() {
      try {
        const res = await listAllTemplates()
        this.templates = (res.data || []).filter(t => t.status === 1)
      } catch (e) {
        try {
          const res2 = await listAllTemplates()
          this.templates = res2.data || []
        } catch (e2) { /* 静默 */ }
      }
    },
    async onTemplateChange(id) {
      if (!id) {
        this.templateNodes = []
        this.currentNode = null
        this.currentNodeIndex = 0
        return
      }
      try {
        const res = await getTemplateWithNodes(id)
        const data = res.data || res
        this.templateNodes = data.nodes || []
        this.currentNodeIndex = 0
        if (this.templateNodes.length > 0) {
          this.currentNode = this.templateNodes[0]
        }
      } catch (e) {
        this.templateNodes = []
      }
    },

    async sendMessage() {
      const text = this.inputMsg.trim()
      if (!text || !this.selectedTemplateId) return

      const now = this.formatTime(new Date())
      this.messages.push({ role: 'customer', content: text, time: now, nodeName: null })
      this.inputMsg = ''
      this.loading = true
      this.$nextTick(() => this.scrollToBottom())

      try {
        const res = await simulateChat({
          templateId: this.selectedTemplateId,
          content: text,
          simulateDate: this.simulateDate
        })

        const reply = typeof res.data === 'string' ? res.data : (res.data?.reply || res.data?.data || '')
        const replyTime = this.formatTime(new Date())

        // 记录节点日志
        const currentNodeInfo = this.currentNode || { nodeName: '消息节点', nodeType: 2 }
        this.nodeLogs.push({
          time: replyTime,
          nodeName: currentNodeInfo.nodeName,
          nodeType: currentNodeInfo.nodeType,
          input: text,
          output: reply,
          duration: null,
          error: null
        })

        // 构建评分（模拟：后端未就绪时前端临时展示）
        const mockScore = reply ? Math.min(5, Math.max(2, Math.round(reply.length / 100))) : 3

        this.messages.push({
          role: 'ai',
          content: reply || '(AI未返回内容)',
          time: replyTime,
          nodeName: currentNodeInfo.nodeName,
          score: mockScore
        })

        // 逐节点模式推进
        if (this.testMode === 'step' && this.templateNodes.length > 0) {
          this.currentNodeIndex = Math.min(this.currentNodeIndex + 1, this.templateNodes.length)
          if (this.currentNodeIndex < this.templateNodes.length) {
            this.currentNode = this.templateNodes[this.currentNodeIndex]
          }
        }
      } catch (e) {
        const errTime = this.formatTime(new Date())
        this.nodeLogs.push({
          time: errTime,
          nodeName: this.currentNode?.nodeName || '未知',
          nodeType: this.currentNode?.nodeType || 2,
          input: text,
          output: null,
          duration: null,
          error: e.message || '模拟对话请求失败'
        })
        this.messages.push({
          role: 'ai',
          content: '[错误] 模拟对话失败: ' + (e.message || '未知错误'),
          time: errTime,
          nodeName: this.currentNode?.nodeName,
          score: 0
        })
      } finally {
        this.loading = false
        this.$nextTick(() => this.scrollToBottom())
      }
    },

    resetChat() {
      this.messages = []
      this.nodeLogs = []
      this.currentNodeIndex = 0
      if (this.templateNodes.length > 0) {
        this.currentNode = this.templateNodes[0]
      }
    },

    scrollToBottom() {
      const el = this.$refs.chatMessages
      if (el) el.scrollTop = el.scrollHeight
    },

    formatTime(date) {
      const h = String(date.getHours()).padStart(2, '0')
      const m = String(date.getMinutes()).padStart(2, '0')
      const s = String(date.getSeconds()).padStart(2, '0')
      return `${h}:${m}:${s}`
    },
    formatDate(date) {
      const y = date.getFullYear()
      const mo = String(date.getMonth() + 1).padStart(2, '0')
      const d = String(date.getDate()).padStart(2, '0')
      const h = String(date.getHours()).padStart(2, '0')
      const mi = String(date.getMinutes()).padStart(2, '0')
      const s = String(date.getSeconds()).padStart(2, '0')
      return `${y}-${mo}-${d} ${h}:${mi}:${s}`
    },

    getNodeTypeText(type) {
      const map = { 1:'开始', 2:'消息', 3:'判断', 4:'等待', 5:'结束', 6:'API', 7:'购物车', 8:'优惠券', 9:'标签', 10:'赠礼', 11:'文档', 12:'用户', 13:'数据分析', 14:'AI' }
      return map[type] || '未知'
    },
    getNodeIcon(type) {
      const map = { 1:'el-icon-video-play', 2:'el-icon-message', 3:'el-icon-question', 4:'el-icon-time', 5:'el-icon-video-pause', 6:'el-icon-link', 14:'el-icon-magic-stick' }
      return map[type] || 'el-icon-circle-check'
    },
    getNodeColor(type) {
      const map = { 1:'#22c55e', 2:'#3b82f6', 3:'#f59e0b', 4:'#8b5cf6', 5:'#ef4444', 6:'#6366f1', 14:'#ec4899' }
      return map[type] || '#909399'
    },
    getNodeTagType(type) {
      if (type === 1) return 'success'
      if (type === 2) return ''
      if (type === 3) return 'warning'
      if (type === 4) return 'info'
      if (type === 5) return 'danger'
      return 'info'
    }
  }
}
</script>

<style scoped>
.chat-test-page {
  display: flex; height: calc(100vh - 84px); gap: 0;
  position: absolute; top: 0; left: 0; right: 0; bottom: 0;
}
.left-panel { width: 280px; flex-shrink: 0; overflow-y: auto; border-right: 1px solid #e8ecf1; padding: 12px; }
.center-panel { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.right-panel { width: 320px; flex-shrink: 0; overflow-y: auto; border-left: 1px solid #e8ecf1; padding: 12px; }

.card-header { display: flex; justify-content: space-between; align-items: center; }
.section-title { font-size: 13px; color: #606266; font-weight: 600; margin: 12px 0 8px; padding-left: 4px; border-left: 3px solid #409EFF; }
.node-preview { margin-top: 12px; }

.chat-container { display: flex; flex-direction: column; height: 100%; background: #f5f7fa; }
.chat-header { padding: 12px 16px; background: #fff; border-bottom: 1px solid #e8ecf1;
  display: flex; justify-content: space-between; align-items: center; font-size: 14px; font-weight: 600; }
.chat-messages { flex: 1; overflow-y: auto; padding: 16px; }
.chat-empty { text-align: center; padding: 80px 20px; color: #c0c4cc; }
.chat-empty i { font-size: 48px; }
.chat-empty p { margin-top: 12px; font-size: 13px; }

.message-row { display: flex; margin-bottom: 16px; }
.message-right { justify-content: flex-end; }
.message-left { justify-content: flex-start; }
.message-bubble { max-width: 75%; padding: 10px 14px; border-radius: 12px; position: relative; }
.message-bubble.customer { background: #409EFF; color: #fff; border-bottom-right-radius: 4px; }
.message-bubble.ai { background: #fff; color: #303133; border-bottom-left-radius: 4px; box-shadow: 0 1px 4px rgba(0,0,0,0.06); }
.message-bubble.typing { background: #fff; color: #909399; font-style: italic; }
.message-meta { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; font-size: 11px; opacity: 0.8; }
.message-bubble.customer .message-meta { color: rgba(255,255,255,0.85); }
.message-bubble.ai .message-meta { color: #909399; }
.message-node-tag { margin-left: auto; }
.message-content { white-space: pre-wrap; word-break: break-word; line-height: 1.5; }
.message-score { margin-top: 6px; display: flex; align-items: center; gap: 6px; }
.score-label { font-size: 11px; color: #909399; }

.chat-input-area { padding: 12px 16px; background: #fff; border-top: 1px solid #e8ecf1; }
.chat-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 8px; }

.log-empty { text-align: center; padding: 40px 20px; color: #c0c4cc; }
.log-empty i { font-size: 36px; }
.log-empty p { margin-top: 8px; font-size: 12px; }
.log-card { margin-bottom: 2px; }
.log-header { display: flex; align-items: center; gap: 8px; }
.log-node-name { font-weight: 600; flex: 1; }
.log-duration { font-size: 11px; color: #909399; }
.log-section { margin-top: 6px; }
.log-label { font-size: 11px; color: #909399; margin-bottom: 2px; }
.log-content { font-size: 12px; padding: 6px 8px; background: #f5f7fa; border-radius: 4px; word-break: break-word; }
.log-content.output { background: #ecf5ff; }
.log-error { font-size: 12px; color: #F56C6C; margin-top: 4px; }

.detail-card { height: 100%; }
</style>
