<template>
  <div class="im-chat-panel" v-loading="loading">
    <div v-if="errorMsg" class="im-error">
      <i class="el-icon-warning-outline"></i>
      {{ errorMsg }}
      <el-button v-if="canRetry" type="text" @click="init">重试</el-button>
    </div>

    <div v-else class="im-layout">
      <!-- 左侧会话列表 -->
      <div class="conv-list">
        <div v-if="!conversations.length && !loading" class="empty">暂无会话</div>
        <div v-for="conv in conversations" :key="conv.conversationID"
          class="conv-item" :class="{ active: current && current.conversationID === conv.conversationID }"
          @click="openConv(conv)">
          <div class="conv-avatar" :style="avatarStyle(conv)">{{ avatarText(conv) }}</div>
          <div class="conv-body">
            <div class="conv-title">
              <span class="conv-name">{{ conv.showName || '未命名' }}</span>
              <span class="conv-time">{{ formatTime(conv.latestMsgSendTime) }}</span>
            </div>
            <div class="conv-snippet">
              <span class="snippet">{{ snippet(conv) }}</span>
              <span v-if="conv.unreadCount > 0" class="badge">{{ conv.unreadCount > 99 ? '99+' : conv.unreadCount }}</span>
            </div>
          </div>
        </div>
      </div>

      <!-- 右侧消息 -->
      <div class="msg-pane">
        <template v-if="current">
          <div class="msg-header">{{ current.showName || '未命名' }}</div>
          <div class="msg-list" ref="msgListRef">
            <div v-for="m in messages" :key="m.clientMsgID"
              class="msg-row" :class="{ mine: m.sendID === myUserId }">
              <div class="msg-bubble">
                <div class="msg-meta">{{ m.senderNickname || m.sendID }} · {{ formatTime(m.sendTime) }}</div>
                <div class="msg-text">{{ renderText(m) }}</div>
              </div>
            </div>
            <div v-if="!messages.length" class="empty">无消息</div>
          </div>
          <div class="msg-input">
            <el-input v-model="draft" size="mini" placeholder="输入消息，回车发送"
              @keyup.enter.native="send" />
            <el-button type="primary" size="mini" :disabled="!draft.trim()" @click="send">发送</el-button>
          </div>
        </template>
        <div v-else class="empty pick-conv">从左侧选择一个会话</div>
      </div>
    </div>
  </div>
</template>

<script>
import { getImCredentials } from '@/api/system/im'
import { im, imBus, MessageType } from '@/utils/imClient'

export default {
  name: 'ImChatPanel',
  data () {
    return {
      loading: false,
      errorMsg: '',
      canRetry: false,
      conversations: [],
      current: null,
      messages: [],
      draft: '',
      myUserId: ''
    }
  },
  created () {
    this.init()
    imBus.$on('new-message', this.onNewMessage)
    imBus.$on('conv-changed', this.refreshConversations)
    imBus.$on('disconnected', () => { this.errorMsg = 'IM 断线，尝试重连…'; this.canRetry = true })
  },
  beforeDestroy () {
    imBus.$off('new-message', this.onNewMessage)
    imBus.$off('conv-changed', this.refreshConversations)
  },
  methods: {
    async init () {
      this.loading = true
      this.errorMsg = ''
      try {
        const res = await getImCredentials()
        if (!res || res.code !== 200 || !res.data) {
          this.errorMsg = (res && res.msg) || '获取 IM 凭据失败'
          this.canRetry = true
          return
        }
        const cred = res.data
        const ok = await im.login(cred)
        if (!ok) {
          const e = im.lastError
          const detail = e && (e.errMsg || e.message || JSON.stringify(e))
          this.errorMsg = '登录 IM 失败：' + (detail || '未知原因（查看 Console）')
          this.canRetry = true
          return
        }
        this.myUserId = cred.imUserId
        await this.refreshConversations()
      } catch (e) {
        this.errorMsg = e.message || '初始化失败'
        this.canRetry = true
      } finally {
        this.loading = false
      }
    },
    async refreshConversations () {
      this.conversations = await im.getConversations(0, 50)
    },
    async openConv (conv) {
      this.current = conv
      this.messages = await im.getMessages(conv.conversationID, 30)
      this.$nextTick(() => this.scrollBottom())
      im.markRead(conv.conversationID)
    },
    async send () {
      if (!this.current || !this.draft.trim()) return
      const text = this.draft
      this.draft = ''
      try {
        await im.sendText(this.current, text)
        const newMessages = await im.getMessages(this.current.conversationID, 30)
        this.messages = newMessages
        this.$nextTick(() => this.scrollBottom())
      } catch (e) {
        this.$message.error('发送失败：' + (e.message || e))
      }
    },
    onNewMessage (msg) {
      // 当前会话的消息追加
      if (this.current && msg && this.current.conversationID === msg.conversationID) {
        this.messages.push(msg)
        this.$nextTick(() => this.scrollBottom())
        im.markRead(this.current.conversationID)
      }
      // 异步刷新会话列表（未读、最新消息）
      this.refreshConversations()
    },
    scrollBottom () {
      const el = this.$refs.msgListRef
      if (el) el.scrollTop = el.scrollHeight
    },
    snippet (conv) {
      const t = conv.latestMsg
      if (!t) return ''
      try {
        const m = JSON.parse(t)
        if (m.textElem) return m.textElem.content
        if (m.pictureElem) return '[图片]'
        if (m.voiceElem) return '[语音]'
        if (m.fileElem) return '[文件]'
        if (m.contentType === 110) return '[系统通知] ' + (m.customElem && JSON.parse(m.customElem.data || '{}').title || '')
        return ''
      } catch (e) { return '' }
    },
    renderText (m) {
      if (!m) return ''
      if (m.contentType === MessageType.TextMessage) return m.textElem && m.textElem.content
      if (m.contentType === MessageType.PictureMessage) return '[图片]'
      if (m.contentType === MessageType.VoiceMessage) return '[语音]'
      if (m.contentType === MessageType.FileMessage) return '[文件] ' + (m.fileElem && m.fileElem.fileName || '')
      if (m.contentType === 110) {
        try {
          const data = JSON.parse(m.customElem && m.customElem.data || '{}')
          return '[系统通知] ' + (data.title || '') + ' · ' + (data.description || '')
        } catch (e) { return '[系统通知]' }
      }
      return '[暂不支持的消息]'
    },
    avatarText (conv) {
      const s = (conv.showName || '?').trim()
      return s.charAt(s.length - 1) || '?'
    },
    avatarStyle (conv) {
      const COLORS = ['#409eff', '#67c23a', '#e6a23c', '#f56c6c', '#909399', '#a06bf3']
      const hash = (conv.conversationID || '').split('').reduce((a, c) => a + c.charCodeAt(0), 0)
      return { background: COLORS[hash % COLORS.length] }
    },
    formatTime (t) {
      if (!t) return ''
      const d = new Date(typeof t === 'number' && t < 1e12 ? t * 1000 : t)
      const now = new Date()
      if (d.toDateString() === now.toDateString()) {
        return d.getHours().toString().padStart(2, '0') + ':' + d.getMinutes().toString().padStart(2, '0')
      }
      return (d.getMonth() + 1) + '/' + d.getDate()
    }
  }
}
</script>

<style lang="scss" scoped>
.im-chat-panel { height: 100%; min-height: 240px; font-size: 12px; }
.im-error {
  padding: 24px; text-align: center; color: #f56c6c;
  i { font-size: 24px; display: block; margin-bottom: 6px; }
}
.im-layout { display: flex; height: 100%; gap: 8px; }
.conv-list {
  flex: 0 0 38%;
  border-right: 1px solid #ebeef5;
  overflow-y: auto;
  padding-right: 4px;
}
.empty { color: #c0c4cc; text-align: center; padding: 24px 0; }
.pick-conv { padding-top: 80px; }
.conv-item {
  display: flex; gap: 6px; padding: 6px 4px; cursor: pointer;
  border-radius: 4px;
  transition: background .15s;
  &:hover { background: #f5f7fa; }
  &.active { background: #ecf5ff; }
}
.conv-avatar {
  flex: 0 0 32px; width: 32px; height: 32px; border-radius: 50%;
  color: #fff; font-size: 13px; font-weight: 600;
  display: flex; align-items: center; justify-content: center;
}
.conv-body { flex: 1; min-width: 0; }
.conv-title {
  display: flex; justify-content: space-between; align-items: center;
  .conv-name { font-weight: 600; color: #303133; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .conv-time { color: #909399; font-size: 10px; flex-shrink: 0; margin-left: 4px; }
}
.conv-snippet {
  display: flex; justify-content: space-between; align-items: center;
  .snippet { color: #909399; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .badge {
    background: #f56c6c; color: #fff;
    border-radius: 9px; padding: 0 5px;
    font-size: 10px; line-height: 14px; height: 14px; min-width: 14px;
    text-align: center; flex-shrink: 0; margin-left: 4px;
  }
}
.msg-pane {
  flex: 1; display: flex; flex-direction: column; min-width: 0;
}
.msg-header {
  padding: 6px 8px; border-bottom: 1px solid #ebeef5;
  font-weight: 600; color: #303133;
}
.msg-list {
  flex: 1; overflow-y: auto; padding: 8px 4px;
}
.msg-row {
  margin-bottom: 6px;
  display: flex;
}
.msg-row.mine { justify-content: flex-end; }
.msg-bubble {
  max-width: 80%;
  background: #f0f0f0;
  border-radius: 4px;
  padding: 4px 8px;
}
.msg-row.mine .msg-bubble { background: #ecf5ff; }
.msg-meta { color: #909399; font-size: 10px; margin-bottom: 2px; }
.msg-text { color: #303133; word-break: break-word; }
.msg-input {
  display: flex; gap: 4px; padding: 6px 4px;
  border-top: 1px solid #ebeef5;
}
.msg-input .el-input { flex: 1; }
</style>
