<template>
  <view class="ai-page">
    <view class="header">
      <text class="title">💊 AI 药典助手</text>
      <text class="subtitle">基于《中华人民共和国药典》& Qwen 大模型</text>
    </view>

    <scroll-view class="chat-list" scroll-y :scroll-top="scrollTop" :scroll-with-animation="true">
      <view v-if="messages.length === 0" class="welcome">
        <text class="welcome-icon">🔬</text>
        <text>输入药品名称、成分或用药问题</text>
      </view>

      <view v-for="(msg, idx) in messages" :key="idx" class="msg-wrapper">
        <!-- 用户消息 -->
        <view v-if="msg.role === 'user'" class="msg-user">
          <text class="msg-content">{{ msg.content }}</text>
        </view>
        <!-- AI 消息 -->
        <view v-else class="msg-ai">
          <view class="msg-tag" :class="tagClass(msg.intent)">
            {{ msg.intent ? intentLabel(msg.intent) : 'AI 药典助手' }}
          </view>
          <!-- 思考中 -->
          <view v-if="msg.thinking" class="thinking">
            <view class="think-dot"></view>
            <text>{{ msg.thinking }}</text>
          </view>
          <!-- 正文 -->
          <rich-text class="msg-body" :nodes="renderMarkdown(msg.content)"></rich-text>
          <!-- 来源 -->
          <view v-if="msg.sources && msg.sources.length" class="msg-sources">
            <text>📚 </text>
            <text v-for="(s, si) in msg.sources.slice(0,3)" :key="si" class="src-item">
              {{ s.section || s.name || '' }} ({{ (s.score || 0).toFixed(2) }})
              <text v-if="si < Math.min(2, msg.sources.length-1)"> · </text>
            </text>
          </view>
        </view>
      </view>
    </scroll-view>

    <!-- 队列提示 -->
    <view v-if="queueCount > 0" class="queue-hint">⏳ 还有 {{ queueCount }} 个问题等待回答</view>

    <!-- 媒体预览 -->
    <view v-if="pendingMedia" class="media-preview">
      <image v-if="pendingMedia.type==='image'" :src="pendingMedia.preview" mode="aspectFit" class="preview-thumb"/>
      <video v-if="pendingMedia.type==='video'" :src="pendingMedia.preview" class="preview-vid"/>
      <text class="preview-name">{{ pendingMedia.type==='video'?'🎬':'📷' }} {{ pendingMedia.name }}</text>
      <text class="preview-remove" @click="clearMedia">✕</text>
    </view>

    <view class="tags">
      <text class="tag-btn" @click="quickAsk('阿莫西林禁忌')">阿莫西林禁忌</text>
      <text class="tag-btn" @click="quickAsk('二甲双胍不良反应')">二甲双胍不良反应</text>
      <text class="tag-btn" @click="quickAsk('布洛芬用法用量')">布洛芬用法用量</text>
      <text class="tag-btn" @click="quickAsk('感冒发烧吃什么药')">感冒发烧吃什么药</text>
    </view>

    <view class="input-area">
      <text class="media-btn" @click="pickImage">📷</text>
      <text class="media-btn" @click="pickVideo">🎬</text>
      <input
        v-model="inputText"
        class="chat-input"
        :placeholder="pendingMedia?(pendingMedia.type==='video'?'视频已就绪，可输入补充问题...':'图片已就绪，可输入补充问题...'):'输入药品问题...'"
        :disabled="streaming"
        @confirm="sendMessage"
        confirm-type="send"
      />
      <button class="send-btn" :disabled="!inputText.trim() && !pendingMedia" @click="sendMessage">{{pendingMedia?'发送(含附件)':'发送'}}</button>
      <button v-if="streaming" class="stop-btn" @click="stopCurrent">停止</button>
    </view>
  </view>
</template>

<script>
import { chatStream } from '@/api/ai.js'

export default {
  data() {
    return {
      messages: [],
      inputText: '',
      conversationId: '',
      streaming: false,
      queueCount: 0,
      messageQueue: [],
      scrollTop: 0,
      currentIntent: '',
      abortFlag: false,
      pendingMedia: null  // {type:'image'|'video', base64:'...', mime:'...', name:'...', preview:'...'}
    }
  },
  methods: {
    intentLabel(i) {
      const m = { drug_query:'药品查询', usage_guide:'用法用量', symptom_advice:'用药建议',
                   regulation:'法规条款', exam_tutor:'考试辅导' }
      return m[i] || '综合查询'
    },
    tagClass(i) {
      const m = { drug_query:'tag-drug', usage_guide:'tag-usage', symptom_advice:'tag-symptom',
                   regulation:'tag-regulation', exam_tutor:'tag-exam' }
      return m[i] || ''
    },

    renderMarkdown(content) {
      if (!content) return ''
      let h = content
        .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
      h = h.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
      // 修复残缺括号
      var secs='(?:结论|详细说明|注意事项|来源明细|适应症|适应证|用法与用量|用法用量|禁忌|不良反应|副作用|药理|药物相互作用|贮藏|特殊人群|安全提醒|就医指征|非药物建议|用药建议|用药方案|通用药学知识|来源汇总|AI 声明|AI声明|来源说明|免责声明)';
      h = h.replace(new RegExp('(?<![【])】\\s*('+secs+')','g'),'【$1】');
      h = h.replace(new RegExp('(?<![【])('+secs+')】','g'),'【$1】');
      h = h.replace(/\n\n+/g, '</p><p>')
      h = h.replace(/\n/g, '<br>')
      // 段落标题：吞掉紧跟的 <br>
      h = h.replace(/【(.+?)】(?:<br>)?/g, '<p style="font-size:30rpx;color:#002FA7;font-weight:bold;margin:14rpx 0 2rpx">【$1】</p>')
      // 去掉标题 <p> 前后的 <br>（避免标题自带 margin + <br> = 多余空行）
      h = h.replace(/<br><p style="font-size:30rpx/g, '<p style="font-size:30rpx')
      h = h.replace(/<\/p><br>/g, '</p>')
      // markdown 链接 [文字](url) → <a>
      h = h.replace(/\[([^\]]+)\]\((https?:\/\/[^\s<>)]+)\)/g, '<a href="$2" style="color:#002FA7;text-decoration:underline">$1</a>')
      // 纯 URL 自动转可点击链接
      h = h.replace(/(?<!href=")(?<!href=')(https?:\/\/[^\s<>]+)/g, '<a href="$1" style="color:#002FA7;text-decoration:underline;word-break:break-all">$1</a>')
      return '<div style="font-size:28rpx;line-height:1.8;color:#1a1a2e;word-break:break-all">' + h + '</div>'
    },

    // ============================================================
    // 媒体选择（图片/视频）
    // ============================================================
    pickImage() {
      uni.chooseImage({
        count: 1, sizeType: ['compressed'],
        success: (res) => {
          const path = res.tempFilePaths[0]
          this.fileToBase64(path, 'image', (b64, info) => {
            this.pendingMedia = { type: 'image', base64: b64, mime: info.mime, name: info.name, preview: path }
          })
        }
      })
    },
    pickVideo() {
      uni.chooseVideo({
        maxDuration: 60, compressed: true,
        success: (res) => {
          const path = res.tempFilePath
          this.fileToBase64(path, 'video', (b64, info) => {
            this.pendingMedia = { type: 'video', base64: b64, mime: info.mime, name: info.name, preview: path }
          })
        }
      })
    },
    fileToBase64(path, type, cb) {
      // uni-app 文件转 base64
      const fs = uni.getFileSystemManager()
      try {
        const data = fs.readFileSync(path, 'base64')
        const name = path.split('/').pop() || (type === 'video' ? 'video.mp4' : 'photo.jpg')
        const mime = type === 'video' ? 'video/mp4' : 'image/jpeg'
        cb(data, { mime, name })
      } catch (e) {
        uni.showToast({ title: '读取文件失败', icon: 'none' })
      }
    },
    clearMedia() {
      this.pendingMedia = null
    },

    quickAsk(text) {
      this.inputText = text
      this.sendMessage()
    },

    sendMessage() {
      const text = this.inputText.trim()
      const hasMedia = !!this.pendingMedia
      if (!text && !hasMedia) return
      this.inputText = ''
      const payload = { text, media: this.pendingMedia }
      this.pendingMedia = null
      this.messageQueue.push(payload)
      this.queueCount = this.messageQueue.length
      if (!this.streaming) this.processQueue()
    },

    stopCurrent() {
      this.abortFlag = true
      this.messageQueue = []
      this.queueCount = 0
      // 最后一个 AI 消息追加停止标记
      if (this.messages.length) {
        const last = this.messages[this.messages.length - 1]
        if (last.role === 'assistant') {
          last.content += ' ⏹ 已停止'
          last.thinking = ''
        }
      }
      this.streaming = false
    },

    async processQueue() {
      if (this.streaming || this.messageQueue.length === 0) return
      this.streaming = true
      this.abortFlag = false
      const payload = this.messageQueue.shift()
      this.queueCount = this.messageQueue.length
      const text = typeof payload === 'string' ? payload : (payload.text || '')
      const media = (typeof payload === 'string') ? null : payload.media

      // 构造用户消息显示
      let userDisplay = text
      if (media) {
        const icon = media.type === 'video' ? '🎬 [视频] ' : '📷 [图片] '
        userDisplay = icon + (text || ('请分析此' + (media.type === 'video' ? '视频' : '图片')))
      }
      this.messages.push({ role: 'user', content: userDisplay })
      const aiIdx = this.messages.length
      this.messages.push({ role: 'assistant', content: '', intent: '', sources: [], thinking: '正在分析问题...' })
      this.scrollToBottom()

      // 构建请求体（支持多媒体）
      const reqBody = { message: text, conversation_id: this.conversationId }
      if (media) {
        reqBody.media_type = media.type
        reqBody.media_base64 = media.base64
        reqBody.media_mime = media.mime
      }

      await chatStream(
        reqBody,
        {
          onIntent: (d) => {
            if (this.abortFlag) return
            this.currentIntent = d
            this.messages[aiIdx].intent = d
          },
          onStatus: (d) => {
            if (this.abortFlag) return
            this.messages[aiIdx].thinking = d
            this.scrollToBottom()
          },
          onToken: (d) => {
            if (this.abortFlag) return
            this.messages[aiIdx].thinking = ''
            this.messages[aiIdx].content += d
            this.scrollToBottom()
          },
          onMeta: (meta) => {
            if (meta.cid) this.conversationId = meta.cid
            if (meta.intent) this.messages[aiIdx].intent = meta.intent
            if (meta.sources) this.messages[aiIdx].sources = meta.sources
          },
          onDone: () => {
            this.messages[aiIdx].thinking = ''
            this.scrollToBottom()
          },
          onError: (err) => {
            if (!this.abortFlag) this.messages[aiIdx].content = '请求失败：' + (err.message || '网络异常')
          }
        }
      )

      this.streaming = false
      this.scrollToBottom()
      if (this.messageQueue.length > 0 && !this.abortFlag) {
        setTimeout(() => this.processQueue(), 300)
      }
    },

    scrollToBottom() {
      this.$nextTick(() => {
        this.scrollTop = 999999
      })
    }
  }
}
</script>

<style scoped>
.ai-page { display: flex; flex-direction: column; height: 100vh; background: #F5F6FA; }
.header { padding: 24rpx 32rpx 16rpx; background: linear-gradient(135deg, #002FA7, #1a3fbf); color: #fff; text-align: center; position: relative; overflow: hidden; }
.header::after { content: ''; position: absolute; top: -40rpx; right: -30rpx; width: 120rpx; height: 120rpx; background: #C41E3A; border-radius: 50%; opacity: .15; }
.title { font-size: 36rpx; font-weight: 700; position: relative; z-index: 1; }
.subtitle { font-size: 24rpx; opacity: .85; margin-top: 8rpx; position: relative; z-index: 1; display: block; }

.chat-list { flex: 1; padding: 16rpx 24rpx; }
.msg-wrapper { margin-bottom: 24rpx; }
.msg-user { display: flex; justify-content: flex-end; }
.msg-user .msg-content { background: #002FA7; color: #fff; padding: 16rpx 24rpx; border-radius: 16rpx 16rpx 4rpx 16rpx; max-width: 80%; font-size: 28rpx; line-height: 1.6; }

.msg-ai { background: #fff; padding: 20rpx 24rpx; border-radius: 0 16rpx 16rpx 16rpx; border-left: 6rpx solid #002FA7; box-shadow: 0 2rpx 8rpx rgba(0,0,0,.06); }
.msg-tag { display: inline-block; font-size: 22rpx; padding: 2rpx 12rpx; border-radius: 10rpx; margin-bottom: 8rpx; font-weight: 600; }
.tag-drug { background: #E8EDF8; color: #002FA7; }
.tag-usage { background: #FDEAEE; color: #C41E3A; }
.tag-symptom { background: #fff3e0; color: #e65100; }
.tag-regulation { background: #f3e5f5; color: #6a1b9a; }
.tag-exam { background: #e0f2f1; color: #00695c; }

.thinking { color: #888; font-size: 26rpx; padding: 4rpx 0; display: flex; align-items: center; }
.think-dot { width: 14rpx; height: 14rpx; border-radius: 50%; background: #002FA7; margin-right: 12rpx; animation: pulse 1s infinite; }
@keyframes pulse { 0%,100% { opacity: 1; transform: scale(1); } 50% { opacity: .4; transform: scale(.7); } }

.msg-body { font-size: 28rpx; line-height: 1.8; color: #1a1a2e; word-break: break-all; }
.msg-body h3 { font-size: 30rpx; color: #002FA7; margin: 16rpx 0 8rpx; }
.msg-body strong { color: #111; }
.msg-body p { margin: 0 0 12rpx 0; }

.msg-sources { margin-top: 16rpx; padding-top: 12rpx; border-top: 1rpx solid #eee; font-size: 22rpx; color: #aaa; }
.src-item { color: #888; }

.queue-hint { text-align: center; padding: 8rpx; font-size: 24rpx; color: #888; background: #fafafa; }

.tags { display: flex; gap: 12rpx; padding: 12rpx 24rpx 16rpx; flex-wrap: wrap; }
.tag-btn { font-size: 24rpx; color: #002FA7; background: #E8EDF8; padding: 8rpx 20rpx; border-radius: 20rpx; border: 1rpx solid rgba(0,47,167,.2); }

.media-preview { display: flex; align-items: center; padding: 12rpx 24rpx; background: #fafafa; border-top: 1rpx solid #eee; gap: 12rpx; }
.preview-thumb { width: 80rpx; height: 80rpx; border-radius: 8rpx; flex-shrink: 0; }
.preview-vid { width: 120rpx; height: 80rpx; border-radius: 8rpx; flex-shrink: 0; }
.preview-name { font-size: 24rpx; color: #888; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.preview-remove { font-size: 28rpx; color: #C41E3A; padding: 8rpx; }

.input-area { display: flex; align-items: center; padding: 16rpx 24rpx; background: #fff; border-top: 1rpx solid #e0e0e0; gap: 12rpx; }
.media-btn { font-size: 36rpx; padding: 8rpx; min-width: 56rpx; text-align: center; }
.chat-input { flex: 1; height: 72rpx; font-size: 28rpx; background: #F5F6FA; border-radius: 40rpx; padding: 0 24rpx; }
.send-btn { background: #C41E3A; color: #fff; border: none; border-radius: 40rpx; padding: 12rpx 28rpx; font-size: 26rpx; font-weight: 700; }
.send-btn[disabled] { opacity: .4; }
.stop-btn { background: #999; color: #fff; border: none; border-radius: 40rpx; padding: 12rpx 28rpx; font-size: 26rpx; }

.welcome { text-align: center; color: #888; padding: 80rpx 40rpx; }
.welcome-icon { font-size: 80rpx; display: block; margin-bottom: 20rpx; }
</style>
