<!--
  Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.

  https://www.mall4j.com/

  未经允许，不可做商业用途！

  版权所有，侵权必究！
-->

<template>
  <view class="Mall4j page-chat content">
    <!-- use-chat-record-mode：开启聊天记录模式 -->
    <!-- safe-area-inset-bottom：开启底部安全区域适配 -->
    <!-- bottom-bg-color：设置slot="bottom"容器的背景色，这里设置为和chat-input-bar的背景色一致 -->
    <!-- #ifdef H5 -->
    <view
      class="shop-info"
    >
      <image
        class="back-icon"
        src="../../static/images/chat/down-arrow.png"
        @tap="backToPre"
      />
      <view
        class="shop-tit"
      >
        {{ userName || $t('xiaoXiHeZi') }}
      </view>
      <view
        class="customer-service"
        @tap="openServicePopup"
      >
        {{ $t('zhuanJieKeFu') }}
      </view>
    </view>
    <!-- #endif -->
    <z-paging
      ref="paging"
      v-model="dataList"
      :auto="false"
      use-chat-record-mode
      safe-area-inset-bottom
      :paging-style="{'background-color': '#f5f6fa', top: '100rpx'}"
      bottom-bg-color="#f8f8f8"
      @query="pullLast"
      @keyboard-height-change="keyboardHeightChange"
      @hided-keyboard="hidedKeyboard"
    >
      <!-- for循环渲染聊天记录列表 -->
      <view
        v-for="(item,index) in dataList"
        :key="item.timestamp"
        style="position: relative;"
      >
        <!-- 如果要给聊天item添加长按的popup，请在popup标签上写style="transform: scaleY(-1);"，注意style="transform: scaleY(-1);"不要写在最外层，否则可能导致popup被其他聊天item盖住 -->
        <!-- <view class="popup" style="transform: scaleY(-1);">popUp</view> -->

        <!-- style="transform: scaleY(-1)"必须写，否则会导致列表倒置 -->
        <!-- 注意不要直接在chat-item组件标签上设置style，因为在微信小程序中是无效的，请包一层view -->
        <view style="transform: scaleY(-1);">
          <chat-item
            :item="item"
            :max-read-seq="maxReadSeq"
            :send-fail-seqs="sendFailSeqs"
            :send-status-obj="sendStatusObj"
            @to-prod-detail="toProdDetail"
          />
          <view
            v-if="index===0"
            class="sys-tips"
          >
            <text class="tips-content">
              {{ loginOtherSide?$t('chat.loginOtherSide') :'' }}
            </text>
          </view>
        </view>
      </view>

      <!-- 底部聊天输入框 -->
      <template #bottom>
        <chat-input-bar
          ref="inputBar"
          @send-image="sendImage"
          @send="doSend"
        />
      </template>
    </z-paging>
    <uni-popup
      ref="customerServiceRef"
      type="bottom"
    >
      <view class="optionType">
        <view class="title">
          <text>{{ $t('xuanZeQiTaZaiXianKeFu') }}</text>
          <view
            class="close iconfont"
            @tap="onCustomerService(1)"
          >
            &#xe60e;
          </view>
        </view>
        <template v-if="serviceList&&serviceList.length">
          <view
            v-for="(item, index) in serviceList"
            :key="index"
            :class="['list', serviceUid == item.uid ? 'active' : '']"
            @tap="selectService(item)"
          >
            <view class="option iconfont">
              &#xe659;
            </view>
            <text class="trans-name">
              {{ item.nickName }}
            </text>
          </view>
        </template>
        <view
          v-else
          class="serviceList-empty-wrap"
        >
          {{ $t('zanWuShuJu') }}
        </view>
        <view class="delivery">
          <button
            class="button"
            type="primary"
            @tap="onCustomerService"
          >
            {{ $t('queDing') }}
          </button>
        </view>
      </view>
    </uni-popup>
  </view>
</template>

<script setup>
import util from '@/utils/util'
import { WKSDK, ChannelTypeGroup, Channel, MessageText, PullMode, ConversationAction, ChannelManager } from 'wukongimjssdk'
import { Convert } from '@/utils/convert'
import chatItem from '@/components/chat-item/chat-item.vue'
// 文字消息
const textMsg = ref('')
const shopInfo = ref(null)
const loginOtherSide = false // 判断用户是否在别处登录
const chatScrollTop = ref(0)
let currentUserId = ''
const userName = ref('')
let sensitiveReplace = ''// 敏感词
const userStore = useUserStore()
const shopId = computed(() => userStore.shopId)
let isDestroy = 0
const paging = ref(null)

onLoad((option) => {
  getShopInfo()
  currentUserId = option.userId
  userName.value = option.userName
  isDestroy = +option.isDestroy
  uni.setNavigationBarTitle({
    title: $t('xiaoXiHeZi')
  })
  getWuKongIm()
  WKSDK.shared().chatManager.addCMDListener(cmdListener) // 监听cmd消息
})
onShow(() => {
  uni.setNavigationBarTitle({
    title: $t('keFu')
  })
})
onUnload(() => {
  WKSDK.shared().chatManager.removeMessageListener(messageListener)
  WKSDK.shared().chatManager.removeCMDListener(cmdListener)
})
const inputBar = ref(null)
// 监听键盘高度改变，请不要直接通过uni.onKeyboardHeightChange监听，否则可能导致z-paging内置的键盘高度改变监听失效
const keyboardHeightChange = (res) => {
  inputBar.value.updateKeyboardHeightChange(res)
}

// 用户尝试隐藏键盘，此时如果图片面板在展示中，应当通知chatInputBar隐藏图片面板
const hidedKeyboard = () => {
  inputBar.value.hidedKeyboard()
}
/**
 * 返回上一页
 */
const prodId = ''
const backToPre = () => {
  const canNavBack = getCurrentPages()
  if (prodId) {
    uni.navigateTo({ url: '/pages/prod/prod?prodid=' + prodId })
  } else {
    if (shopId.value == 0) {
      if (canNavBack && canNavBack.length > 1) {
        uni.navigateBack({
          delta: 1
        })
      } else {
        history.back()
      }
    } else {
      uni.navigateBack({
        url: '/package-user/pages/chat/chat'
      })
    }
  }
}
/**
 * 获取店铺信息
 */
const getShopInfo = () => {
  const params = {
    url: '/shop/shopDetail/info',
    method: 'GET',
    data: {
      shopId: shopId.value
    }
  }
  http.request(params).then(({ data: res }) => {
    shopInfo.value = res
  })
}

// 判断是否为JSON格式
const isJSON = (str) => {
  if (typeof str == 'string') {
    try {
      JSON.parse(str)
      return true
    } catch (e) {
      return false
    }
  }
}

/**
 * 发送信息
 */
const sendText = async () => {
  if (isDestroy || isDestroyArr.includes(to.value.channelID)) {
    uni.showToast({
      title: $t('zhangHuYiZhuXiao'),
      icon: 'none'
    })
    textMsg.value = ''
    return
  }
  if (!noAccountable) {
    textMsg.value = ''
    uni.showToast({
      title: $t('buShiNiFuZeDeKeHu'),
      icon: 'none'
    })
    return
  }
  // type 1 = 发送消息  type 2 = 发送商品链接
  // source 0 是平台  1 是商家  2 是顾客
  if (textMsg.value === '' || !currentUserId || textMsg.value.match(/^\s+$/)) {
    uni.showToast({
      title: $t('buNengFaSongKongBaiXiaoXiO'),
      icon: 'none'
    })
    return
  }
  await getSensitiveWords(textMsg.value)

  let content = ''
  const msgObj = JSON.stringify({ msg: textMsg.value, msgType: 1, sender: -1 })
  content = new MessageText(msgObj)
  WKSDK.shared().chatManager.send(content, to.value)
  textMsg.value = ''
}
const doSend = (msg) => {
  textMsg.value = msg
  sendText(1)
}
/**
 * @param {Object} type
 * 选照片 or 拍照
 */
const sendImage = (type) => {
  if (isDestroy || isDestroyArr.includes(to.value.channelID)) {
    uni.showToast({
      title: $t('zhangHuYiZhuXiao-0'),
      icon: 'none'
    })
    textMsg.value = ''
    return
  }
  if (!noAccountable) {
    textMsg.value = ''
    uni.showToast({
      title: $t('buShiNiFuZeDeKeHu-0'),
      icon: 'none'
    })
    return
  }
  util.chooseImage({ sourceType: [type], sizeType: ['original', 'compressed'], count: 9 }).then(data => {
    data.forEach((item) => {
      const msgObj = JSON.stringify({ msg: item.filePath, msgType: 2 })
      const content = new MessageText(msgObj)
      WKSDK.shared().chatManager.send(content, to.value)
    })
  })
}

/**
 * 链接点击去往商品详情
 */
const toProdDetail = (prodInfo, type) => {
  if (type === 0) {
    uni.navigateTo({
      url: `/package-prod/pages/prod-management/prod-management?prodId=${prodInfo.prodId}`
    })
  } else {
    uni.navigateTo({
      url: `/package-order/pages/order-detail/order-detail?orderNumber=${prodInfo.orderNumber}&userId=${currentUserId}`
    })
  }
}
// 敏感词
const getSensitiveWords = async (message) => {
  const { data } = await http.request({
    url: '/sensitive/replace',
    method: 'post',
    data: message
  })
  sensitiveReplace = data
  textMsg.value = sensitiveReplace
}
let messageListener
const getWuKongIm = () => {
  getShopChannelInfo()
  // 监听消息发送状态
  listenMsgSendStatus()
  messageListener = (msg) => {
    if (isJSON(msg.content.text)) {
      msg.content.text = JSON.parse(msg.content.text)
    }
    const type = msg.content.text.type
    if (type === -1 && msg.channel.channelID === to.value.channelID) {
      http.request({ url: '/shop/wuKongIm/getShopChannelInfo?userId=' + currentUserId, method: 'POST' })
    }
    const lastMessage = messages.value[messages.value.length - 1]
    if (msg.send && type !== -1 && msg.content.text.msgType !== -1 && updateAuto && (lastMessage || (lastMessage && lastMessage?.send === false))) {
      http.request({ url: '/shop/wuKongIm/updateAuto?channelId=' + msg.channel.channelID, method: 'POST' })
      updateAuto = false
    }

    msg.messageSeq = ++lastMessageSeq // 新发送的消息没有序列号,此处添加序列号
    http.request({ url: '/shop/wuKongIm/conversations/setUnread', data: { channel_id: to.value.channelID, maxSeq: lastMessageSeq }, method: 'POST' })
    if (to.value.channelID === msg.channel.channelID) {
      if (msg.content.text.sender === 1) {
        http.request({ url: '/shop/wuKongIm/getShopChannelInfo?userId=' + currentUserId, method: 'POST' }).then(({ data }) => {
          noAccountable = !!data.isWhiteUser
        })
      }
      if (messages.value.length) {
        const prevTime = util.tsToDate(
          messages.value[messages.value.length - 1].timestamp * 1000,
          'M-D h:m'
        )
        const nowTime = util.tsToDate(new Date().getTime(), 'M-D h:m')
        if (prevTime.slice(0, prevTime.indexOf(' ')) === nowTime.slice(0, nowTime.indexOf(' '))) {
          msg.timeStr = util.tsToDate(new Date().getTime(), 'h:m')
        } else {
          msg.timeStr = util.tsToDate(new Date().getTime(), 'M-D h:m')
        }
        const timeFlag = util.timeBeApart(messages.value[messages.value.length - 1].timestamp * 1000, new Date().getTime())
        if (timeFlag) {
          delete msg.timeStr
        }
      } else {
        msg.timeStr = util.tsToDate(new Date().getTime(), 'M-D h:m')
      }
      if (!to.value.isEqual(msg.channel)) {
        return
      }
      if (msg.clientSeq) {
        if (!getApp().globalData.connectSuccess) {
          sendFailSeqs.value.push(msg.clientSeq)
        } else if (sendStatusObj.value[msg.clientSeq] !== false) {
          sendStatusObj.value[msg.clientSeq] = true
        }
      }
      messages.value.push(msg)
      paging.value.addChatRecordData(msg)
      nextTick(() => {
        chatScrollTop.value = chatScrollTop.value + 1000 * messages.value.length
      })
    }
  }
  WKSDK.shared().chatManager.addMessageListener(messageListener)
}

const sendFailSeqs = ref([])
const sendStatusObj = ref({}) // clientSeq为key，value为加载状态
let messageStatusListener
const listenMsgSendStatus = () => {
  sendFailSeqs.value = [] // 清空发送失败的seqs
  WKSDK.shared().chatManager.removeMessageStatusListener(messageStatusListener)
  messageStatusListener = (ack) => {
    if (ack.reasonCode !== 1) {
      // eslint-disable-next-line no-console
      console.log('消息发送失败=>>', ack)
      sendFailSeqs.value.push(ack.clientSeq)
    }
    sendStatusObj.value[ack.clientSeq] = false
  }
  WKSDK.shared().chatManager.addMessageStatusListener(messageStatusListener)
}

const maxReadSeq = ref(0)
const to = ref(new Channel('', ChannelTypeGroup))
let updateAuto = false
let noAccountable = false
const getShopChannelInfo = () => {
  const params = {
    url: '/shop/wuKongIm/getShopChannelInfo?userId=' + currentUserId,
    method: 'POST'
  }
  http.request(params).then(async ({ data }) => {
    if (data) {
      noAccountable = !!data.isWhiteUser
      if (data.imChannel.sendAutoReply === 1) {
        updateAuto = isDateBeforeToday(data.imChannel.personReplyTime)
      }
      http.request({ url: '/shop/wuKongIm/conversations/setUnread', method: 'POST', data: { channel_id: data.imChannel.channelId, maxSeq: data.imChannel.userReadSeq } })
      maxReadSeq.value = data.imChannel.userReadSeq

      to.value.channelID = data.imChannel.channelId
      await fetchChannelInfoIfNeed(to.value)
      clearConversationUnread(to.value)
      paging.value.reload()
    }
  })
}
const isDateBeforeToday = (dateTimeString) => {
  if (!dateTimeString) {
    return true
  }
  // 将日期时间字符串转换为日期对象
  const givenDate = new Date(dateTimeString)
  // 获取当前日期的年、月、日
  const today = new Date()
  const todayYear = today.getFullYear()
  const todayMonth = today.getMonth()
  const todayDay = today.getDate()
  givenDate.setHours(0, 0, 0, 0)
  return (
    givenDate.getFullYear() < todayYear ||
    (givenDate.getMonth() < todayMonth && givenDate.getFullYear() === todayYear) ||
    (givenDate.getDate() < todayDay &&
      givenDate.getMonth() === todayMonth &&
      givenDate.getFullYear() === todayYear)
  )
}
// 获取某个频道的最近会话
const clearConversationUnread = (channel) => {
  const conversation = WKSDK.shared().conversationManager.findConversation(channel)
  if (conversation) {
    conversation.unread = 0
    WKSDK.shared().conversationManager.notifyConversationListeners(conversation, ConversationAction.update)
  }
}
let lastMessageSeq = 0
const messages = ref([])
const dataList = ref([])
const pullLast = async (pageNum, pageSize) => {
  const msgs = await WKSDK.shared().chatManager.syncMessages(to.value, {
    pageNum,
    pageSize,
    pullMode: pageNum === 1 ? PullMode.Up : PullMode.Down
  })
  messages.value = []

  lastMessageSeq = msgs[msgs.length - 1]?.messageSeq || msgs[msgs.length - 2]?.messageSeq || 0// 最后一条消息可能是商品链接即取倒数第二条
  if (msgs && msgs.length > 0) {
    msgs.forEach((m) => {
      messages.value.push(m)
    })
  }
  paging.value.complete([...messages.value].reverse())
}
// 同步自己业务端的频道消息列表
// 同步自己业务端的频道消息列表
let moreMsg = 0
WKSDK.shared().config.provider.syncMessagesCallback = async (channel, opts) => {
  const resultMessages = []
  const firstMsg = messages.value[0]
  if (firstMsg && (messages.value[0]?.messageSeq === 1 || !messages.value[0]?.messageSeq)) {
    return
  }
  const params = {
    url: '/shop/wuKongIm/channel/messageSyncH5',
    method: 'get',
    data: {
      channel_id: channel.channelID,
      channel_type: channel.channelType,
      start_message_seq: firstMsg?.messageSeq - 1 || 0,
      pull_mode: opts.pullMode,
      current: opts.pageNum,
      size: opts.pageSize
    }
  }
  const { data } = await http.request(params)
  moreMsg = data.more
  if (!moreMsg) {
    uni.showToast({
      title: $t('yiQuanBuJiaZaiWanBi'),
      icon: 'none'
    })
  }
  const messageList = data && data.messages
  if (messageList?.[0].messageSeq === 1) {
    moreMsg = 0
  }
  if (messageList) {
    messageList.forEach((msg) => {
      const message = Convert.toMessage(msg)
      message.content.text = JSON.parse(message.content.text)
      message.timeStr = util.tsToDate(
        message.timestamp * 1000,
        'M-D h:m'
      )
      resultMessages.push(message)
    })

    resultMessages.length > 0 && resultMessages.reduce((prev, cur) => {
      // 将时间更换为某某月某某日 要是是当天即去掉月日
      const now = util.tsToDate(prev.timestamp * 1000, 'M-D h:m')
      const next = util.tsToDate(cur.timestamp * 1000, 'M-D h:m')
      if (
        now.slice(0, now.indexOf(' ')) ===
            next.slice(0, next.indexOf(' '))
      ) {
        cur.timeStr = util.tsToDate(cur.timestamp * 1000, 'h:m')
      }

      // 历史记录进行时间段显示判断
      if (resultMessages.length > 2) {
        const timeFlag = util.timeBeApart(prev.timestamp * 1000, cur.timestamp * 1000)
        if (timeFlag) {
          delete cur.timeStr
        }
      }
      return cur
    })
  }

  return resultMessages
}
const channelInfo = ref()

const fetchChannelInfoIfNeed = async (channel) => {
  if (channel) {
    channelInfo.value = WKSDK.shared().channelManager.getChannelInfo(channel)// 获取频道详情(不会触发数据源的远程获取)

    if (!channelInfo.value) {
      await WKSDK.shared().channelManager.fetchChannelInfo(channel)
    }
  }
}
WKSDK.shared().config.provider.channelInfoCallback = async (channel) => {
  const { data } = await http.request({ url: '/shop/wuKongIm/listChannelSubcribers?channelId=' + channel.channelID, method: 'GET' })
  const channelInfo = {
    logo: data.subscribers[0]?.pic,
    title: data.shopName,
    shopId: data.shopId,
    data: data.subscribers,
    channel
  }
  return channelInfo
}
// 监听cmd消息
let shopStatus = false
const isDestroyArr = []
const cmdListener = async (msg) => {
  if (msg.content.contentObj.cmd === 'memberUpdate') {
    ChannelManager.shared().channelInfocacheMap = {}
  }

  if (msg.content.contentObj.cmd === 'userDestroy') {
    isDestroyArr.push(msg.content.contentObj.param)
  }
  if (isJSON(msg.content.contentObj.content)) {
    msg.content.contentObj.content = JSON.parse(msg.content.contentObj.content)
    if (msg.content.contentObj.content.type === -2) {
      maxReadSeq.value = msg.content.contentObj.content.content// 已读的最大序列号
    }
  }
  if (msg.content.contentObj?.cmd === 'shopStatus') {
    shopStatus = true
  }
}
// 获取在线客服列表
const customerServiceRef = ref(null)
const serviceList = ref([])
const openServicePopup = () => {
  if (isDestroy || isDestroyArr.includes(to.value.channelID)) {
    uni.showToast({
      title: $t('zhangHuYiZhuXiao-1'),
      icon: 'none'
    })
    return
  }
  http.request({
    url: '/shop/wuKongIm/listTransfer',
    method: 'GET'
  }).then(({ data }) => { // 客服列表
    serviceList.value = data
  })
  customerServiceRef.value.open('bottom')
}
const onCustomerService = (type) => {
  if (type !== 1) {
    if (shopInfo.value.shopStatus !== 1 || shopStatus) {
      uni.showToast({
        title: $t('shangJiaYiXiaXianQingHuiFuShangXian'),
        icon: 'none'
      })
      return
    }
    if (isDestroy || isDestroyArr.includes(to.value.channelID)) {
      uni.showToast({
        title: $t('zhangHuYiZhuXiao-2'),
        icon: 'none'
      })
      textMsg.value = ''
      return
    }
    if (!noAccountable) {
      textMsg.value = ''
      uni.showToast({
        title: $t('buShiNiFuZeDeKeHu-1'),
        icon: 'none'
      })
      return
    }
    if (selectItem.uid) {
      http.request({
        url: '/shop/wuKongIm/transfer?channelId=' + to.value.channelID + '&uid=' + selectItem.uid,
        method: 'post'
      }).then(() => {
        getShopChannelInfo()
        uni.showToast({
          title: $t('zhuanJieKeFuChengGong'),
          icon: 'none',
          success: () => {
            uni.switchTab({
              url: '/pages/message-box/message-box'
            })
          }
        })
      })
      customerServiceRef.value.close()
    } else {
      uni.showToast({
        title: $t('qingXuanZeYiGeKeFuZhuanJie'),
        icon: 'none'
      })
    }
  } else {
    customerServiceRef.value.close()
  }
}
const serviceUid = ref('')
let selectItem = {}
// 选择的客服
const selectService = (item) => {
  selectItem = item
  serviceUid.value = item.uid
}
</script>

<style lang="scss" scoped>
@use "./chat.scss";
</style>
