packages/customerService/index/index<template>
  <view class="chat-container">
    <!-- 聊天头部 -->
    <view :style="{ paddingTop: top + 'px', height: localHeight + 'px' }" class="chat-header">
      <view class="back-btn" @tap="goBack">
        <uni-icons color="#333" size="28" type="left"></uni-icons>
      </view>
      <view class="chat-title">{{ chatTarget.title || '客服' }}</view>
      <view class="change-service-btn" @tap="goToChangeService">
        <uni-icons color="#333" size="22" type="switch"></uni-icons>
      </view>
    </view>

    <!-- 连接状态提示 -->
    <view v-if="connectingStatus" class="connecting-status">{{ connectingStatus }}</view>

    <!-- 聊天消息区域 -->
    <scroll-view :scroll-into-view="scrollToView" class="chat-messages" scroll-y="true" @scrolltoupper="loadMoreHistory"
      @scrolltolower="loadMoreHistory" lower-threshold="100" upper-threshold="100">
      <!-- 加载历史消息提示 -->
      <view v-if="isLoadingHistory" class="message-time">加载历史消息...</view>

      <!-- 消息列表 -->
      <block v-for="(message, index) in messages" :key="index">
        <!-- 时间分割线 -->
        <view v-if="needShowTime(index)" class="message-time">{{ formatTime(message.time) }}</view>

        <!-- 消息项 -->
        <view :id="'msg-' + index" :class="{
          'self': message.isSelf,
          'other': !message.isSelf,
          'loading': message.isLoading
        }" class="message-item">
          <image :src="message.isSelf ? userAvatar : (chatTarget.employee_image)" class="message-avatar"
            mode="aspectFill"></image>
          <view class="message-content">
            {{ message.content }}
          </view>
        </view>
      </block>
    </scroll-view>

    <!-- 输入区域 -->
    <view class="chat-input-area">
      <view class="input-container">
        <textarea v-model="inputMessage" :adjust-position="true" class="message-input" placeholder="请输入消息..."
          @confirm="sendMessage" @input="handleInput" auto-height hold-keyboard="true"
          enable-keyboard-accessory-view="true" cursor-spacing="10" maxlength="500" @focus="onInputFocus"
          @blur="onInputBlur"></textarea>
        <button :disabled="!canSend || !client || !isConnected" class="send-btn" @tap="sendMessage">
          发送
        </button>
      </view>
    </view>
  </view>
</template>

<script>
import { picUrl, menuButtonInfo, request, NavgateTo } from "../../../utils";
import { apiArr } from '@/api/customerService'
import mqttTool from '@/utils/mqtt'

export default {
  data() {
    return {
      localHeight: '',
      top: '',
      // 聊天目标信息
      chatTarget: {
        mchId: '',
        title: '',
        avatar: '',
        openId: '' // 接收方的open_id
      },
      // 用户头像
      userAvatar: '',
      // 消息列表
      messages: [],
      // 输入的消息
      inputMessage: '',
      // 是否可以发送消息
      canSend: false,
      // 连接状态
      isConnected: false,
      // 连接状态文本
      connectingStatus: '',
      // 滚动到指定视图
      scrollToView: '',
      // 是否加载历史消息
      isLoadingHistory: false,
      // 心跳包定时器
      keepaliveTimer: null,
      selfClientId: uni.getStorageSync('openId'),
      // MQTT工具实例
      client: null,
      mqttConfig: {},
      // 重连失败提示定时器
      reconnectFailedTimer: null,
      // 分页参数
      pageNum: 1,
      pageSize: 10,
      // 是否还有更多历史消息
      hasMoreHistory: true,
      // 滚动到底部的标记
      scrollToBottomFlag: false
    }
  },
  onLoad(options) {
    const meun = menuButtonInfo()
    this.top = meun.top
    this.localHeight = meun.height
    // 获取聊天对象信息
    if (options.item) {
      this.chatTarget = JSON.parse(options.item)
      this.chatTarget.title = `客服${this.chatTarget.employee_name}`
    }
    // 初始化MQTT连接
    this.initChat()
    this.getMqttConfig()
    // 初始化用户头像
    this.userAvatar = picUrl + uni.getStorageSync('headPhoto')
  },
  onShow() {
  },
  methods: {
    async connect() {
      this.client = null
      const options = {
        clientId: this.selfClientId
      }

      // 添加连接状态回调
      const callbacks = {
        onConnect: () => {
          console.log('客服连接成功')
          this.isConnected = true
          this.connectingStatus = ''
        },
        onDisconnect: this.onDisconnect.bind(this),
        onError: (error) => {
          console.error('客服连接错误:', error)
          this.isConnected = false
          this.connectingStatus = '连接错误，请重试'
        },
        onReconnect: () => {
          console.log('客服正在重连...')
          this.isConnected = false
          this.connectingStatus = '连接已断开，正在重连...'
        }
      }

      this.client = mqttTool.connect(options, callbacks)
      this.isConnected = !!this.client

      await this.subscribe()
      this.client.on('message', (topic, message) => {
        const msgStr = Buffer.from(message).toString('utf8'); // 二进制转UTF-8字符串
        const msg = JSON.parse(msgStr); // 后续解析逻辑不变

        let jsMsg = msg // 直接使用已解析的对象，无需再次解析
        console.log('收到消息', topic, msg)
        if (jsMsg.send_client === this.selfClientId || jsMsg.receive_client === this.selfClientId) {
          console.log('接收或发送人是我')
          if (jsMsg.send_client === this.mqttConfig.clientId || jsMsg.receive_client === this.mqttConfig.clientId) {
            console.log('接收或发送人是我的聊天对象')
            this.messages.push({
              content: jsMsg.content,
              time: Date.now(),
              isSelf: jsMsg.send_client === this.selfClientId,
              isLoading: false
            })
            console.log('收到我的消息', this.messages)
            this.scrollToView = 'msg-' + (this.messages.length - 1)
          }
        }
      })
    },
    async subscribe() {
      if (this.isConnected && this.client) {
        this.client.subscribe('contact/message/receive_msg', { qos: 0 }, (err) => {
          if (!err) {
            console.log('订阅成功', 'contact/message/receive_msg', { qos: 0 })
            this.connectingStatus = ''
          } else {
            console.log('订阅失败:', err)
            this.connectingStatus = '订阅失败，请重试'
          }
        })
      } else {
        console.log('连接失败', this.isConnected, this.client)
        this.connectingStatus = '连接失败，请重试'
      }
    },
    // 初始化聊天
    async initChat() {
      try {
        // 显示连接状态
        this.connectingStatus = '正在连接客服...'
        await this.connect()
        // 连接成功后启动心跳包
        this.startKeepalive()
        // 连接成功后立即加载历史消息
        this.loadHistoryMessages()
      } catch (error) {
        console.error('初始化聊天失败', error)
        this.connectingStatus = '连接失败，请检查网络'

        // 失败后尝试重新连接
        this.reconnectFailedTimer = setTimeout(() => {
          this.initChat()
        }, 3000)
      }
    },

    // 获取MQTT连接配置
    async getMqttConfig() {
      try {
        // 如果没有已创建的实例或clientId，则通过API获取
        return new Promise((resolve, reject) => {
          const params = {
            worker_id: this.chatTarget.id || '',
            open_id: this.selfClientId || ''
          }
          request(apiArr.csGetToClientId, 'POST', params).then((res) => {
            console.log('聊天列表:', res)
            // 检查响应数据格式是否正确
            if (res && res.client_bind && res.client_bind.client_id_one && res.client_bind.client_id_two) {
              this.mqttConfig.clientId = res.client_bind.client_id_one // 登录人的open_id
              this.chatTarget.openId = res.client_bind.client_id_two // 接收方的open_id
              this.mqttConfig.bind_id = res.client_bind.id
              resolve()
            } else {
              console.error('MQTT配置响应格式不正确:', res)
              reject(new Error('未获取到有效的MQTT配置'))
            }
          }).catch(error => {
            console.error('获取MQTT配置失败', error)
            reject(error)
          })
        })
      } catch (error) {
        console.error('获取MQTT配置失败', error)
        throw error
      }
    },

    // MQTT断开连接回调
    onDisconnect(packet) {
      console.log('MQTT连接断开', packet)
      this.isConnected = false
      this.client = null

      // 根据断开原因设置不同的连接状态文本
      if (packet && packet.error) {
        // 连接失败的情况
        this.connectingStatus = '连接失败，请检查网络'
      } else {
        // 其他断开连接的情况
        this.connectingStatus = '连接已断开，正在重连...'
      }

      // 停止心跳包
      this.stopKeepalive()
    },

    // 加载历史消息
    async loadHistoryMessages() {
      if (!this.hasMoreHistory || this.isLoadingHistory) {
        return
      }

      try {
        this.isLoadingHistory = true

        // 确保已经获取了mqttConfig.bind_id
        if (!this.mqttConfig.bind_id) {
          await this.getMqttConfig()
        }

        const params = {
          bind_id: this.mqttConfig.bind_id,
          order: 'desc', // 按时间降序排列
          page_num: this.pageNum,
          page_size: this.pageSize
        }

        console.log('请求历史消息参数:', params)
        const res = await request(apiArr.csGetMsgRecord, 'POST', params)

        console.log('历史消息返回结果:', res)
        if (res && res.code === 1 && res.data && res.data.msg_record) {
          const historyMessages = res.data.msg_record

          // 如果没有更多历史消息了
          if (historyMessages.length === 0) {
            this.hasMoreHistory = false
            return
          }

          // 将获取到的历史消息添加到消息列表开头
          // 这里需要根据消息的发送方判断是否是自己发送的消息
          const formattedMessages = historyMessages.map(msg => ({
            content: msg.content,
            time: new Date(msg.create_time).getTime(),
            isSelf: msg.send_client === this.mqttConfig.clientId,
            isLoading: false
          })).reverse() // 因为是按时间降序获取的，所以需要反转

          // 添加到消息列表开头
          this.messages = [...formattedMessages, ...this.messages]

          // 增加页码
          this.pageNum++
        }
      } catch (error) {
        console.error('加载历史消息失败', error)
      } finally {
        this.isLoadingHistory = false
      }
    },

    // 加载更多历史消息
    loadMoreHistory() {
      if (!this.isLoadingHistory && this.hasMoreHistory) {
        this.loadHistoryMessages()
      }
    },

    // 发送消息
    sendMessage() {
      const content = this.inputMessage.trim()
      console.log('发送消息', content)
      if (!content || !this.client || !this.isConnected) return
      // 滚动到底部
      this.scrollToBottom()
      console.log('需要发送的对象', this.mqttConfig)
      // 按照用户提供的格式构建发送消息
      const msgData = {
        bind_id: this.mqttConfig.bind_id, // 聊天列表的ID，这里暂时固定为1
        send_client: this.mqttConfig.clientId, // 消息发送方open_id 
        receive_client: this.chatTarget.openId, // 消息接收方open_id 
        type: 1, // 消息类型，1表示文字消息
        content: content, // 消息内容
        receive_read_status: 2 // 接收方阅读状态
      }
      console.log('发送消息', msgData)
      this.client.publish(
        'contact/message/send_msg', // 使用指定的发送消息主题
        JSON.stringify(msgData),
        { Qos: 0 },
        (err) => {
          if (err) {
            console.error('发送消息失败', err)
            // 可以在这里添加消息发送失败的处理逻辑
          } else {
            console.log('发送消息成功')
          }
        }
      )

      // 清空输入框
      this.inputMessage = ''
    },

    // 处理输入事件
    handleInput() {
      this.canSend = this.inputMessage.trim().length > 0
    },

    onInputFocus() {
      // 输入框获取焦点时，设置滚动到底部的标记
      this.scrollToBottomFlag = true;
      setTimeout(() => {
        if (this.scrollToBottomFlag) {
          this.scrollToBottom();
        }
      }, 300);
    },

    onInputBlur() {
      // 输入框失去焦点时，重置滚动标记
      this.scrollToBottomFlag = false;
    },

    // 是否需要显示时间分割线
    needShowTime(index) {
      if (index === 0) return true

      const currentMsg = this.messages[index]
      const prevMsg = this.messages[index - 1]

      // 如果两条消息间隔超过5分钟，则显示时间分割线
      return (currentMsg.time - prevMsg.time) > 5 * 60 * 1000
    },

    // 格式化时间
    formatTime(time) {
      const date = new Date(time)
      const hours = date.getHours().toString().padStart(2, '0')
      const minutes = date.getMinutes().toString().padStart(2, '0')

      return `${hours}:${minutes}`
    },

    // 滚动到底部
    scrollToBottom() {
      setTimeout(() => {
        this.scrollToView = 'msg-' + (this.messages.length - 1)
      }, 100)
    },

    // 返回上一页
    goBack() {
      uni.navigateBack()
    },

    // 启动心跳包 - 增强版：添加错误处理和状态检查
    startKeepalive() {
      // 停止之前的定时器
      this.stopKeepalive()

      // 每30秒发送一次心跳包
      this.keepaliveTimer = setInterval(() => {
        if (this.client && this.isConnected) {
          const keepaliveData = {
            client_id: this.mqttConfig.clientId
          }

          this.client.publish(
            'contact/message/keep_time',
            JSON.stringify(keepaliveData),
            {},
            (err) => {
              if (err) {
                console.error('发送心跳包失败', err)
                // 心跳包发送失败可能表示连接有问题，可以考虑触发重连
                if (!this.isConnected) {
                  return
                }
                console.log('心跳包发送失败，尝试检查连接状态')
                // 这里可以添加额外的连接检查逻辑
              }
            }
          )
        } else {
          console.warn('MQTT未连接，停止心跳包')
          this.stopKeepalive()
        }
      }, 30000)
    },

    // 停止心跳包
    stopKeepalive() {
      if (this.keepaliveTimer) {
        clearInterval(this.keepaliveTimer)
        this.keepaliveTimer = null
      }
    },

    // 跳转到切换客服页面
    goToChangeService() {
      uni.navigateTo({
        url: '/packages/customerService/changeService/index?currentMchId=' + this.chatTarget.mchId
      })
    }
  },

  // 页面卸载时停止心跳包
  onUnload() {
    // 断开MQTT连接
    if (this.client) {
      this.client.disconnect()
    }

    // 停止心跳包
    this.stopKeepalive()

    // 清除重连失败提示定时器
    if (this.reconnectFailedTimer) {
      clearTimeout(this.reconnectFailedTimer)
      this.reconnectFailedTimer = null
    }
  }
}
</script>

<style>
@import url("./index.css");
</style>