<template>
  <div v-if="repealMsg" class="msg-repeal-item">
    {{repealStr}}
  </div>
  <div v-else-if="joinMsg" class="msg-join-item">
    <span>{{joinMsg}}</span>
  </div>
  <redPack-tip
    v-else-if="msgItem && msgItem.redPackTip"
    :info="msgItem">
  </redPack-tip>
  <div class="msg-item clearfix" :class="type" v-else>
    <msg-time :timestamp="timestamp" v-if="timeMsg"></msg-time>
    <img v-if="avatarUrl" class="user-avatar avatar" src="../../assets/loading.gif" :originurl="avatarUrl" @click="clickInfo" alt>
    <div v-else
        class="avatar"
        :class="'avatar_bg' + userId % 9"
        :data-name="name && name.slice(0,2).toUpperCase()"
        @click="clickInfo"
    ></div>
    <div class="content">
      <div class="metabar">
        <span class="name" @contextmenu.prevent="onToolBtn($event,'username')">{{name}}</span>
        <span class="admin" v-if="creator == userId">
          <i class="icon-creator" v-if="type === 'me'"></i>
          {{$t('public.owner')}}
          <i class="icon-creator" v-if="type === 'you'"></i>
        </span>
        <span class="admin" v-else-if="adminList.includes(Number(userId))">
          <i class="el-icon-star-on" v-if="type === 'me'"></i>
          {{$t('public.admin')}}
          <i class="el-icon-star-on" v-if="type === 'you'"></i>
        </span>
        <i class="icon-tele" v-if="msgItem.ext_info && msgItem.ext_info.is_tg"></i>
        <span class="time">{{timestamp|formatTimestamp}}</span>
      </div>
      <red-packet
        v-if="msg_type == 4 && msgItem"
        @click.native="$packetGet(msgItem)"
        :info="msgItem">
      </red-packet>
      <template v-else>
        <bubble-wrap
          :isMobile="isMobile"
          :showToolbar="showToolbar"
          @onTouchStartToolBtn="onTouchStartToolBtn"
          @onTouchEndToolBtn="onTouchEndToolBtn"
          @onToolBtn="onToolBtn"
        >
            <i class="loading-icon" v-if="loading"></i>
            <i class="error-icon" v-if="fail" @click="reSend"></i>
            <a :href="content" target="_blank" v-if="msg_type == 1 && meechatType=='mini' && !isMobile">
              <img class="img-msg"
                  :style="{width:width,height:height}"
                  src="" :originurl="formatUploadImg(content)"
              >
              <i class="pic-loading"></i>
            </a>
            <div v-else-if="msg_type == 1">
              <img
                @click="$showImgPreview(content)"
                class="img-msg"
                :style="{width:width,height:height}"
                src="" :originurl="formatUploadImg(content)"
              >
              <i class="pic-loading"></i>
            </div>
            <video
              class="video-msg"
              :class="{'limit-height': msg_type == 3}"
              controls="controls"
              preload="meta"
              :poster="msgItem.ext_info && msgItem.ext_info.cover_url"
              v-else-if="msg_type == 2 || msg_type == 3"
              :src="content"
            ></video>
            <pre v-else class="text" v-html="content"></pre>

            <template v-if="toolBtnType=='username'">
                <ul @touchstart.stop class="pub-pop-toolbar ext-username" v-show="showToolbar">
                  <li @click.prevent="handleCopy">{{$t('chat.copy')}}</li>
                </ul>
            </template>
            <template v-else>
              <ul @touchstart.stop class="pub-pop-toolbar username" v-show="showToolbar">
                <li @click.prevent="handleQuote" v-if="msg_type == 0 || msg_type == 4">{{$t('chat.quote')}}</li>
                <li @click.prevent="handleCopy">{{$t('chat.copy')}}</li>
                <!-- <li @click.prevent="handleDel">删除</li> -->
                <li class="split-line" v-if="(isAdmin && type === 'you') || (isAdmin || revoke)"></li>
                <li @click.prevent="handlePingMsg" v-if="isAdmin">{{$t('chat.sticky')}}</li>
                <li @click.prevent="handleBlock" v-if="isAdmin && type === 'you'">{{block?$t('chat.liftaBan'):$t('public.ban')}}</li>
                <li @click.prevent="handleRevoke" v-if="isAdmin || revoke">{{$t('chat.revoke')}}</li>
              </ul>
            </template>

        </bubble-wrap>
      </template>
    </div>
  </div>
</template>

<script>
import dayjs from 'dayjs'
import msgTime from '@/components/msgItem/time'
import redPacket from '@/components/msgItem/redPacket'
import redPackTip from '@/components/msgItem/redPackTip'
import bubbleWrap from '@/components/msgItem/bubbleWrap'
import { mapMutations, mapActions, mapState } from 'vuex'
import { getMeechatType } from '@/util/util'

export default {
  name: 'msgItem',
  components: {
    msgTime,
    redPacket,
    redPackTip,
    bubbleWrap
  },
  props: {
    msgItem: Object,
    isPrivate: Boolean,
    repealMsg: Boolean,
    joinMsg: String,
    from: [String, Number],
    timeMsg: Boolean,
    avatar: {
      type: String
    },
    name: {
      type: String
    },
    timestamp: [String, Number],
    hash: String,
    content: {
      type: [String, Number, Object]
    },
    userId: [String, Number],
    /**
     * 消息来源 {me: 我发的, you: 其他人发的}
     */
    type: {
      type: String
    },
    /**
     * 消息种类 (1 => 图片, 2 => 视频, 3 => 音频, 4 => 链接, 5 => 红包)
     */
    msg_type: {
      type: [Number, String]
    },
    createTime: [Number],
    loading: [Boolean],
    fail: [Boolean],
    res: [File, Blob],
    isMobile: Boolean,
    isAdmin: Boolean
  },
  data () {
    return {
      showToolbar: false,
      revoke: false,
      block: false,
      revokeTimeAllow: false,
      width: 'auto',
      height: 'auto',
      longTapTimer: null,
      meechatType: getMeechatType(), // meechat版本
      toolBtnType: ''
    }
  },
  watch: {
    content (val, oldVal) {
      if (this.msg_type != 1 && val == oldVal) return

      this.countPicSize()
    }
  },
  computed: {
    ...mapState({
      curSession: state => state.curSession,
      myId: state => state.userId,
      userInfo: state => state.group.userInfo,
      blockList: state => state.group.blockList,
      adminList: state => state.group.adminList,
      members: state => state.group.members,
      creator: state => state.group.creator
    }),
    isLogin () {
      return !!this.myId
    },
    repealStr () {
      if (this.repealMsg) {
        if (!this.from || this.from == this.userId) {
          return `${this.type == 'me' ? this.$t('public.you') : this.name}${this.$t('chat.revokeMsg')}`
        } else if (this.from != this.userId) {
          let admin = this.members[this.from]
          let adminName = admin ? admin.nick_name : this.$t('public.admin')

          return `${adminName}${this.$t('chat.revoked')}${this.name}${this.$t('chat.aMsg')}`
        } else {
          return `${this.name}${this.$t('chat.revokeMsg')}`
        }
      } else {
        return ''
      }
    },
    avatarUrl () {
      let membersCover = this.members[this.userId] && this.members[this.userId].cover_photo

      return membersCover || this.avatar || ''
    }
  },
  beforeMount () {
    if (this.msg_type == 1) {
      this.countPicSize()
    }
  },
  created () {
  },
  methods: {
    ...mapMutations(['setCopyText', 'updateChatInputFocus', 'reSendChatItem', 'setSessionRepeal']),
    ...mapActions([
      'doRepealPersonMsg',
      'doRepealGroupMsg',
      'doBlockUser',
      'doUnBlockUser',
      'doPinMsg',
      'doSendMsg',
      'doSendFile'
    ]),
    clickInfo () {
      if (!this.isLogin) return

      if (this.meechatType == 'h5') {
        let infoUrl = this.type === 'me' ? '/me' : `/other/${this.userId}`
        this.$router.push(infoUrl)
      } else {
        this.type === 'me' ? this.$showUserInfo() : this.$showOtherInfo(this.userId)
      }
    },
    // 计算图片尺寸
    countPicSize () {
      let rect = /_size([0-9]+)x([0-9]+)/.exec(this.content)
      if (rect) {
        let originalWidth = parseInt(rect[1])
        let originalHeight = parseInt(rect[2])
        // let holderWidth = (document.body.offsetWidth - 35) * 0.84
        let scaleX = originalWidth > 400 ? 400 / originalWidth : 1
        let scaleY = originalHeight > 250 ? 250 / originalHeight : 1
        let scale = Math.min(scaleX, scaleY)
        this.width = scale * originalWidth + 'px'
        this.height = scale * originalHeight + 'px'
      }
    },
    formatUploadImg (val) {
      if (/^data:image/.test(val)) return val
      else return `${val}?imageview/0/w/400`
    },
    hideToolbar (event) {
      if (this.showToolbar !== false) {
        this.showToolbar = false
        document.body.removeEventListener('touchstart', this.hideToolbar, false)
        document.body.removeEventListener('click', this.hideToolbar, false)
        document.body.removeEventListener('contextmenu', this.hideToolbar, false)
      }
    },
    /**
     * @des 触发自定义右键菜单
     * @param {string} type [{'username':仅复制}]
     */
    onToolBtn (event, type) {
      this.toolBtnType = type

      if (this.showToolbar) {
        this.hideToolbar(event)
        return
      }
      if (!this.isMobile) {
        setTimeout(() => {
          document.body.addEventListener('click', this.hideToolbar, false)
          document.body.addEventListener('contextmenu', this.hideToolbar, false)
        }, 0)
      }

      this.showToolbar = true
      this.block = this.blockList.some(id => id == this.userId)
      this.revokeTimeAllow =
        Date.now() - parseInt(this.timestamp) < 1e3 * 60 * 3
      this.revoke = this.type === 'me' && this.revokeTimeAllow
    },
    onTouchStartToolBtn (event) {
      clearTimeout(this.longTapTimer)

      this.longTapTimer = setTimeout(() => {
        this.onToolBtn(event)
      }, 800)
    },
    onTouchEndToolBtn (event) {
      clearTimeout(this.longTapTimer)

      setTimeout(() => {
        document.body.addEventListener('touchstart', this.hideToolbar, false)
        document.body.addEventListener('click', this.hideToolbar, false)
      }, 0)
    },
    // 引用时转换表情标签
    replaceEmoji (content) {
      let emojiReg = /<img class="emoji" .+?\/>/gi
      return content.replace(emojiReg, function (match) {
        let emoji = match.match(/alt=.+?&*"/g)
        let emojiCont = emoji && emoji[0].replace(/"|alt=|/g, '')

        return emojiCont
      })
    },
    // 引用时转换链接标签
    replaceLink (content) {
      let linkReg = /<a href=".+?" class="link text" target="_blank">.+?<\/a>/gi
      return content.replace(linkReg, function (match) {
        let link = match.match(/>.+?&*<\/a>/g)
        let linkCont = link && link[0].replace(/>|<\/a>|/g, '')

        return linkCont
      })
    },
    handleQuote () {
      let { name, content } = this
      let newCont = this.replaceLink(this.replaceEmoji(content))
      let quoteStr = `「${name}：${newCont}」\n- - - - - - - - - - - - - - -\n`
      this.$emit('quoteMsg', quoteStr)
      this.$nextTick(() => {
        this.updateChatInputFocus(true)
      })
    },
    handleCopy () {
      let userSelection
      let selectedText = ''
      if (window.getSelection) { // 现代浏览器
        userSelection = window.getSelection()
        selectedText = userSelection.toString()
      } else if (document.selection) { // IE浏览器 考虑到Opera，应该放在后面
        userSelection = document.selection.createRange()
        selectedText = userSelection.text
      }

      let copyTxt = this.replaceEmoji(selectedText || this.content)
      this.$copyText(copyTxt).then(
        e => {
          this.updateChatInputFocus(true)
        },
        e => {
          console.log('Can not copy')
        }
      )
      this.setCopyText(copyTxt)
    },
    handleShare () {
      this.$showInvite(this.content)
    },
    handleDel () {
      this.$emit('deleteMsg', this.hash)
    },
    handlePingMsg () {
      this.doPinMsg({ hash: this.hash })
    },
    handleRevoke () {
      if (this.isPrivate) {
        this.doRepealPersonMsg({ hash: this.hash }).then((data) => {
          this.$store.commit('setSessionRepeal', {
            me: true,
            sessionId: this.curSession
          })
          this.$store.commit('repealChatItem', {
            hash: this.hash,
            from: this.from
          })
        })
      } else {
        this.doRepealGroupMsg({ hash: this.hash })
      }
    },
    handleBlock () {
      if (this.block) {
        this.doUnBlockUser({ id: this.userId })
      } else {
        this.doBlockUser({ id: this.userId })
      }
    },
    reSend () {
      if (this.msg_type == 0 || this.msg_type == 4) {
        let opt = {
          type: 0,
          msg: this.content,
          createTime: this.createTime
        }
        this.reSendChatItem({ createTime: this.createTime })

        if (this.isPrivate) {
          this.doSendPrivateMsg(opt)
        } else {
          this.doSendMsg(opt)
        }
      } else {
        let opt = {
          res: this.res,
          createTime: this.createTime
        }
        this.reSendChatItem({ createTime: this.createTime })
        this.doSendFile(opt)
      }
    }
  },
  filters: {
    formatTimestamp (val) {
      if (!val) return ''
      return dayjs(val * 1).format('HH:mm')
    }
  }
}
</script>

<style lang="scss">
@import "./style.scss"
</style>
