<template>
  <div v-if="repealMsg" class="msg-repeal-item">
    {{repealStr}}
  </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="avatar"
      class="user-avatar avatar"
      :src="avatar"
      @click="$showOtherInfo(userId)"
      alt
    >
    <div
      v-else
      class="avatar"
      :class="'avatar_bg' + userId % 9"
      :data-name="name.slice(0,2).toUpperCase()"
      @click="$showOtherInfo(userId)"
    ></div>
    <div class="content">
      <div class="metabar">
        <span class="name">{{name}}</span>
        <span class="time">{{timestamp|formatTimestamp}}</span>
      </div>
      <red-packet
        v-if="msg_type == 4 && msgItem"
        @click.native="$packetGet(msgItem)"
        :info="msgItem">
      </red-packet>
      <div v-else class="bubble" :class="{focus:showToolbar}" @contextmenu.prevent.stop="onToolBtn">
        <i class="loading-icon" v-if="loading"></i>
        <i class="error-icon" v-if="fail" @click="reSend"></i>
        <img @click="$showImgPreview(content)" class="img-msg" v-if="msg_type == 1" :style="{width:width,height:height}" :src="content" @load="imgLoad">
        <video class="video-msg"
          :class="{'limit-height': msg_type == 3}"
          controls="controls"
          preload="meta"
          v-else-if="msg_type == 2 || msg_type == 3"
          :src="content">
        </video>
        <pre class="text" v-else-if="msg_type == 10" v-html="content"></pre>
        <pre class="text" v-else>{{content}}</pre>
        <ul class="toolbar" v-show="showToolbar" :style="{left:toolBarX,top:toolBarY,bottom:toolBarBottom}">
          <li @click="handleQuote" v-if="msg_type == 0 || msg_type == 4">引用</li>
          <li @click="handleCopy">复制</li>
          <!-- <li @click="handleDel">删除</li> -->
          <li class="split-line" v-if="(isAdmin && type === 'you') || (isAdmin || revoke)"></li>
          <li @click="handlePingMsg" v-if="isAdmin">置顶</li>
          <li @click="handleBlock" v-if="isAdmin && type === 'you'">{{block?'解禁':'禁言'}}</li>
          <li @click="handleRevoke" v-if="isAdmin || revoke">撤回</li>
        </ul>
      </div>
    </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 { mapMutations, mapActions, mapState } from 'vuex'

export default {
  name: 'msgItem',
  components: {
    msgTime,
    redPacket,
    redPackTip
  },
  props: {
    msgItem: Object,
    isPrivate: Boolean,
    repealMsg: Boolean,
    from: String,
    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]
  },
  data () {
    return {
      interactive: 0, // 1 鼠标 2 touch
      toolBarX: 0,
      toolBarY: 0,
      toolBarBottom: 0,
      showToolbar: false,
      revoke: false,
      block: false,
      revokeTimeAllow: false,
      width: 'auto',
      height: 'auto',
      longtapTimer: null
    }
  },
  computed: {
    ...mapState({
      myId: state => state.userId,
      userInfo: state => state.group.userInfo,
      blockList: state => state.group.blockList,
      adminList: state => state.group.adminList,
      members: state => state.group.members
    }),
    isAdmin () {
      return this.adminList && this.adminList.some(id => id == this.myId)
    },
    repealStr () {
      if (this.repealMsg) {
        if (this.from == this.userId) {
          return `${this.type == 'me' ? '你' : this.name}撤回了一条消息`
        } else {
          let admin = this.members[this.from]
          let adminName = '管理员'
          if (admin) {
            adminName = admin.nick_name
          }
          return `${adminName}撤回了${this.name}的一条消息`
        }
      } else {
        return ''
      }
    }
  },
  mounted () {
    if (this.msg_type == 1) {
      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 > holderWidth ? holderWidth / 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'
      }
    }
  },
  created () {
  },
  methods: {
    ...mapMutations([
      'updateChatInputFocus',
      'reSendChatItem'
    ]),
    ...mapActions([
      'doRepealPersonMsg',
      'doRepealGroupMsg',
      'doBlockUser',
      'doUnBlockUser',
      'doPinMsg',
      'doSendMsg',
      'doSendFile'
    ]),
    imgLoad (e) {
      this.width = 'auto'
      this.height = 'auto'
    },
    hideToolbar (event) {
      if (this.showToolbar !== false) {
        this.showToolbar = false
        document.body.removeEventListener('click', this.hideToolbar, false)
        // document.body.removeEventListener('touchstart', this.hideToolbar, false)
        this.interactive = 0
      }
    },
    onToolBtn (event) {
      console.log(event)
      // if (this.interactive == 2) {
      //   event.preventDefault()
      //   return
      // }

      if (this.showToolbar) {
        this.hideToolbar(event)
        return
      }

      let winWidth = window.innerWidth
      let winHeight = window.innerHeight
      let clientX, clientY

      if (event instanceof MouseEvent) {
        this.interactive = 1
        clientX = event.clientX
        clientY = event.clientY
        this.toolBarX = event.layerX + 20
        this.toolBarY = event.layerY

        this.$nextTick(() => {
          document.body.addEventListener('click', this.hideToolbar, false)
          // document.body.addEventListener('touchstart', this.hideToolbar, false)
        })
      } else {
        this.interactive = 2
        let touch = event.touches[0] || event.changedTouches[0]
        clientX = touch.clientX
        clientY = touch.clientY
        let rect = event.target.getBoundingClientRect()
        this.toolBarX = touch.pageX + 20 - rect.left
        this.toolBarY = touch.pageY - rect.top
        // 校正局部坐标
        let target = event.target
        while (!target.classList.contains('bubble')) {
          this.toolBarX += target.offsetLeft
          target = target.parentNode
        }
      }
      if (clientX > winWidth * 0.66) {
        this.toolBarX = this.toolBarX - 120
      }
      this.toolBarX += 'px'

      if (clientY > winHeight / 2) {
        this.toolBarBottom = this.toolBarY + 'px'
        this.toolBarY = 'auto'
      } else {
        this.toolBarBottom = 'auto'
        this.toolBarY += 'px'
      }

      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
    },
    onTapToolBtn (event) {
      clearTimeout(this.longtapTimer)
      this.longtapTimer = setTimeout(() => {
        this.onToolBtn(event)
      }, 1000)
    },
    clearTapToolBtn () {
      clearTimeout(this.longtapTimer)

      this.$nextTick(() => {
        document.body.addEventListener('click', this.hideToolbar, false)
      })
    },
    handleQuote () {
      let { name, content } = this
      let quoteStr = `「${name}：${content}」\n- - - - - - - - - - - - - - -\n`
      this.$emit('quoteMsg', quoteStr)
      this.$nextTick(() => {
        this.updateChatInputFocus(true)
      })
    },
    handleCopy () {
      this.$copyText(this.content).then(
        e => {
          this.updateChatInputFocus(true)
        },
        e => {
          console.log('Can not copy')
        }
      )
    },
    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 })
      } 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 })
        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" scoped>
@import './style.scss';
</style>
