<script setup>
import { computed } from 'vue'
import { marked } from 'marked'
import DOMPurify from 'dompurify'
import { ChatboxEllipsesOutline, CheckmarkCircle, CloseCircleOutline, EllipseOutline, SparklesOutline } from '@vicons/ionicons5'
import { NIcon, NSpin } from 'naive-ui'

const props = defineProps({ question: String, steps: Array, answer: String, busy: Boolean })

marked.setOptions({ breaks: true, gfm: true })
const renderedAnswer = computed(() => DOMPurify.sanitize(marked.parse(props.answer || '')))

const statusIcon = status => status === 'success' ? CheckmarkCircle : status === 'failed' ? CloseCircleOutline : EllipseOutline
</script>

<template>
  <section class="panel chat-panel">
    <h2><n-icon><ChatboxEllipsesOutline /></n-icon> 问答对话</h2>
    <div v-if="question" class="message user"><span>用户</span><p>{{ question }}</p></div>
    <div class="message system">
      <span>系统检索过程</span>
      <div class="steps">
        <div v-for="step in steps" :key="step.key" class="step" :class="step.status">
          <n-spin v-if="step.status === 'running'" :size="16" />
          <n-icon v-else><component :is="statusIcon(step.status)" /></n-icon>
          <div><strong>{{ step.title }}</strong><small>{{ step.error || step.description }}</small></div>
          <time>{{ step.time }}</time>
        </div>
      </div>
    </div>
    <div class="answer-title"><n-icon><SparklesOutline /></n-icon> AI 回答</div>
    <div class="answer-box" :class="{ empty: !answer }">
      <n-spin v-if="busy && !answer" size="small" description="正在融合证据生成回答..." />
      <div v-else-if="answer" class="answer-text" v-html="renderedAnswer"></div>
      <p v-else>完成检索后，Kimi 将严格依据右侧证据生成回答。</p>
    </div>
  </section>
</template>

<style scoped>
.panel{height:100%;padding:18px;border:1px solid rgba(72,142,220,.28);border-radius:12px;background:rgba(4,18,40,.74);overflow:auto}.panel h2{display:flex;align-items:center;gap:9px;font-size:16px;margin-bottom:16px}.panel h2 .n-icon,.answer-title .n-icon{color:#2aa8ff}.message>span{display:block;color:#91a8c6;font-size:11px;margin:0 0 7px 4px}.message.user{display:flex;flex-direction:column;align-items:flex-end}.message.user p{max-width:84%;padding:13px 16px;border-radius:11px 11px 3px 11px;background:linear-gradient(135deg,#0e3977,#123b7b);border:1px solid rgba(52,139,255,.28);font-size:13px;line-height:1.7}.message.system{margin-top:15px}.steps{padding:5px 12px;border:1px solid rgba(68,137,216,.25);border-radius:10px;background:rgba(8,27,54,.65)}.step{display:grid;grid-template-columns:22px 1fr auto;gap:9px;align-items:center;padding:10px 0;border-bottom:1px solid rgba(80,132,190,.18)}.step:last-child{border:0}.step>.n-icon{font-size:18px;color:#57708e}.step.success>.n-icon{color:#20dc8a}.step.failed>.n-icon{color:#fb7185}.step strong,.step small{display:block}.step strong{font-size:12px}.step small{font-size:11px;color:#8199b9;margin-top:2px}.step time{font-size:10px;color:#637c9b}.answer-title{display:flex;align-items:center;gap:8px;margin:18px 0 9px;font-size:13px;font-weight:700}.answer-box{min-height:165px;padding:16px;border:1px solid rgba(71,139,218,.28);border-radius:10px;background:linear-gradient(135deg,rgba(14,47,83,.72),rgba(8,27,53,.78));font-size:13px;line-height:1.85}.answer-box.empty{display:flex;align-items:center;justify-content:center;color:#66809f;text-align:center}.answer-text{color:#d7e5f5;line-height:1.75;word-break:break-word}.answer-text :deep(h1),.answer-text :deep(h2),.answer-text :deep(h3),.answer-text :deep(h4){color:#f0f7ff;line-height:1.4;margin:16px 0 8px;font-weight:700}.answer-text :deep(h1){font-size:19px}.answer-text :deep(h2){font-size:17px}.answer-text :deep(h3){font-size:15px;color:#bfe0ff}.answer-text :deep(h4){font-size:14px}.answer-text :deep(h1:first-child),.answer-text :deep(h2:first-child),.answer-text :deep(h3:first-child){margin-top:0}.answer-text :deep(p){margin:7px 0}.answer-text :deep(strong){color:#fff;font-weight:700}.answer-text :deep(ul),.answer-text :deep(ol){margin:8px 0;padding-left:23px}.answer-text :deep(li){margin:5px 0;padding-left:2px}.answer-text :deep(li::marker){color:#48a9ff}.answer-text :deep(blockquote){margin:11px 0;padding:8px 12px;border-left:3px solid #2999ef;border-radius:0 6px 6px 0;background:rgba(35,120,202,.12);color:#9fc3e7}.answer-text :deep(code){padding:2px 5px;border:1px solid rgba(86,151,218,.22);border-radius:4px;background:#07182d;color:#78c7ff;font-family:Consolas,monospace;font-size:.88em}.answer-text :deep(pre){margin:10px 0;padding:12px;overflow:auto;border:1px solid rgba(72,139,207,.25);border-radius:7px;background:#051326}.answer-text :deep(pre code){padding:0;border:0;background:transparent;color:#b9d8f4}.answer-text :deep(table){display:block;width:100%;margin:11px 0;overflow:auto;border-collapse:collapse;font-size:11px}.answer-text :deep(th),.answer-text :deep(td){padding:7px 9px;border:1px solid rgba(79,139,203,.3);text-align:left;white-space:nowrap}.answer-text :deep(th){background:rgba(31,86,143,.45);color:#d5ebff}.answer-text :deep(tr:nth-child(even)){background:rgba(24,66,108,.18)}.answer-text :deep(a){color:#55b8ff;text-decoration:none}.answer-text :deep(a:hover){text-decoration:underline}.answer-text :deep(hr){height:1px;margin:15px 0;border:0;background:rgba(88,145,205,.25)}
</style>
