import msgItem from '@/components/msgItem'
import emoji from '@/components/emoji'
import chatAt from '@/components/chatAt'
import atMe from '@/components/chatAt/atme'
import chatPin from '@/components/chatPin'
import toolbar from '@/components/chatInput/toolbar'
import { mapActions, mapState, mapMutations } from 'vuex'
import { getMiniWsUrl } from '@/util/contract.js'
import { isMobile, scrollMsgIntoView, lazyloadImage } from '@/util/util.js'
import WsManager from '@/util/wsManager.js'
import { Message } from 'element-ui'
import ImageMin from '@/util/imageMin.js'
import { chatAtMixin, chatInputMixin, changeLangMixin } from '@/mixins'
import { accountLoginMixin } from '@/mixins/login'
import { emojiList } from '@/util/emoji'
import api from '@/api'
import loginBox from '@/components/login/loginBox'

export default {
  name: 'chatMini',
  mixins: [accountLoginMixin, chatAtMixin, chatInputMixin, changeLangMixin],
  components: {
    msgItem,
    emoji,
    chatAt,
    chatPin,
    atMe,
    toolbar,
    loginBox
  },
  props: {
    width: {
      type: Number,
      default: 274
    },
    height: {
      type: Number,
      default: 390
    },
    show: {
      type: Boolean,
      default: false
    },
    groupId: [Number, String]
  },
  computed: {
    ...mapState([
      'account',
      'group',
      'userId',
      'userInfo'
    ]),
    ...mapState({
      chatInputFocus: state => state.group.chatInputFocus,
      blockList: state => state.group.blockList,
      pinMsg: state => state.group.pinMsg,
      atList: state => state.group.atList,
      chatList: state => state.group.chatList,
      unreadNums: state => state.group.unreadNums,
      sessionList: state => state.chat.sessionList
    }),
    emojiMap () {
      var emojiMap = {}
      for (let i in emojiList) {
        let arr = emojiList[i]
        arr.forEach(v => {
          let names = JSON.stringify(v.names)
          let emoji = v.surrogates
          emojiMap[names] = emoji
        })
      }
      return emojiMap
    },
    linkToCreator () {
      let { creator, userId } = this.group
      let sessionId = creator > userId ? `${userId}-${creator}` : `${creator}-${userId}`
      return `${location.origin}/#/pm/${sessionId}`
    },
    isAdmin () {
      return (this.group.adminList && this.group.adminList.some(id => id == this.userId)) || this.group.creator == this.userId
    }
  },
  data () {
    return {
      loginBoxVisible: false,
      isLoadingRoom: true,
      isMobile: isMobile(),
      showChat: !!this.show, // 显示聊天窗
      showEmoji: false, // 显示表情选择框
      showMenuExtra: false, // 显示左上角菜单
      showLoginBtn: true, // 显示登录按钮
      lockMore: false,
      isScrollToView: false,
      lockEnd: false,
      loading: false,
      unreadCounts: 0, // 未读消息数
      inputMsg: '', // 用户输入的内容
      atInd: 0, // @人索引
      inputHeight: 18,
      enableScroll: false, // 记录滚动条是否激活的状态
      isBottom: true,
      toolShow: false,
      chatImageArrSel: null,
      serverUnRead: 0, // 客服未读
      personUnRead: 0 // 私聊未读
    }
  },
  watch: {
    inputMsg (val, newval) {
      let ele = this.$refs.chatInput
      this.inputHeight = 'auto'

      this.$nextTick(() => {
        this.inputHeight = Math.max(18, Math.min(ele.scrollHeight, 75)) + 'px'
      })
    },
    chatList (val) {
      let lastVal = val[val.length - 1]
      if ((lastVal && lastVal.msg_type == 4) || this.isBottom) {
        // 自己发的红包自动滚动到底部
        this.$nextTick(this.resizeToBottom)
      }
    },
    chatInputFocus (val, newval) {
      if (this.showLoginBtn) return
      let ele = this.$refs.chatInput
      if (val) {
        if (document.activeElement !== ele) {
          this.placeEnd(ele)
          ele.focus()
        }
      } else {
        if (document.activeElement === ele) {
          ele.blur()
        }
      }
    }
  },
  async mounted () {
    // 设置groupId
    this.initGroup({
      userId: this.userId,
      groupId: this.groupId,
      useCache: false
    })

    // 检查登录态
    let isLogin = await this.checkLocalLogin()

    if (isLogin) {
      this.showLoginBtn = false
      await this.getUserInfo()
      console.log('this.account', this.account, 'this.userInfo', this.userInfo)
    }

    this.$nextTick(this.initChat)

    this.$nextTick(this.initMiniSocket)

    document.getElementById('app').addEventListener('contextmenu', e => e.preventDefault())
    document.addEventListener('paste', this.initPaste)
    document.addEventListener('drop', this.initDrop)
    document.addEventListener('dragover', this.initDragOver)

    document.body.addEventListener('click', () => {
      this.showEmoji = false
      this.showMenuExtra = false
      this.toolShow = false
    })
  },
  beforeDestroy () {
    document.removeEventListener('paste', this.initPaste)
    document.removeEventListener('drop', this.initDrop)
    document.removeEventListener('dragover', this.initDragOver)
  },
  methods: {
    ...mapMutations([
      'initGroup',
      'setUserId',
      'setToken',
      'addChatItem',
      'deleteChatItem',
      'updateChatInputFocus',
      'updateGroupBlockList',
      'updateMembers',
      'updateGroupPinMsg',
      'repealChatItem',
      'removeAtListLast',
      'clearAtList',
      'initState',
      'addPacketItem',
      'addPacketTip',
      'addUnreadNums',
      'resetUnreadNums',
      'addPinChatItem'
    ]),
    ...mapActions([
      'getUserInfo',
      'setAccount',
      'doGameLogin',
      'doScatterLogout',
      'getGroupInfo',
      'getNewMsgFromDb',
      'getNewMsg',
      'getHistoryMsg',
      'doSendMsg',
      'doSendFile',
      'updateSessionLastmsg'
    ]),
    handleMoreClick () {
      this.showEmoji = false
      this.toolShow = !this.toolShow

      this.checkNeedToBottom()
    },
    handleEmojiClick () {
      this.toolShow = false
      this.showEmoji = !this.showEmoji

      this.checkNeedToBottom()
    },
    checkNeedToBottom () {
      if (!this.isBottom) return

      this.$nextTick(() => {
        this.resizeToBottom()
      })
    },
    async initMiniLoginCallback () {
      await this.initMiniSocket()
      this.showLoginBtn = false

      this.initGroup({
        userId: this.userId,
        groupId: this.groupId,
        useCache: false
      })

      await this.getUserInfo()
      this.loginBoxVisible = false
    },
    // 连接socket
    initMiniSocket () {
      if (!window.WebSocket) {
        console.log('Error: WebSocket is not supported .')
        return
      }

      let host = getMiniWsUrl() + `?group_id=${this.groupId}`
      if (this.socket) {
        this.socket.destroy()
        this.socket = null
      }

      this.socket = new WsManager(host, {
        autoConnect: true, // 自动连接
        reconnection: true, // 断开自动重连
        reconnectionDelay: 2000 // 重连间隔时间，单位秒
      })

      this.socket.on('open', res => {})

      this.socket.on('message', (data) => {
        data = JSON.parse(data)
        if (data.channel.match('chat:group')) {
          if (data.data.type === 'msg') {
            this.getNewMsg({ newMsg: true })
            if (data.data.from != this.userId) {
              // 未读消息数+1
              if (!this.showChat) {
                if (this.unreadCounts === 0) {
                  this.postResize(130, 50)
                }
                this.unreadCounts++
              } else {
                this.addUnreadNums()
              }
            }
          }

          if (data.data.type === 'repeal') {
            this.repealChatItem(data.data)
          }

          if (data.data.type === 'block') {
            this.updateGroupBlockList({
              type: 'add',
              id: data.data.to
            })
          }

          if (data.data.type === 'unblock') {
            this.updateGroupBlockList({
              type: 'delete',
              id: data.data.to
            })
          }

          if (data.data.type === 'join') {
            this.updateMembers(data.data.user_info)
          }

          if (data.data.type === 'pin_msg') {
            this.updateGroupPinMsg(data.data.pinMsg)
          }

          if (data.data.type === 'unpin_msg') {
            this.updateGroupPinMsg(null)
          }

          if (data.data.type === 'new_redpack') {
            this.addPacketItem(data.data)
            if (data.data.from == this.userId) {
              this.$nextTick(this.resizeToBottom)
            }
          }

          if (data.data.type === 'grab_redpack') {
            if (data.data.from == this.userId || data.data.to == this.userId) {
              this.addPacketTip(data.data)
            }
          }
        }
      })
    },
    /**
     * 聊天群初始化处理
     * 先后调用 group/info, group/msg
     */
    async initChat () {
      this.handleToggleChat(this.show)
      this.isLoadingRoom = true

      await this.getGroupInfo()
      await this.getNewMsgFromDb()
      await this.getNewMsg()

      this.isLoadingRoom = false
      // 有登录态才要请求
      if (!this.showLoginBtn) {
        await this.getPmUnRead()
      }

      if (this.show) {
        this.$nextTick(this.resizeToBottom)
      }

      this.chatImageArrSel = this.$refs.scrollWrap.getElementsByTagName('img')
    },
    getPmUnRead () {
      api.session.getMiniUnRead().then(({ data }) => {
        this.personUnRead = data.data['0']
        this.serverUnRead = data.data[this.groupId] || 0
      })
    },
    /**
     * 清空私聊未读
     * @param {type} 1.客服2.私聊
     **/
    clearPmUnread (type) {
      if (type == 1) this.serverUnRead = 0
      else this.personUnRead = 0
    },
    async handleLogout () {
      this.doScatterLogout()
      this.showLoginBtn = true

      if (self !== top) {
        localStorage.removeItem('account')
        this.postMessager.send({
          action: 'meechat:logout'
        })
      }

      // 初始vuex数据
      this.$store.commit('setUserInfo', null)
      // this.$store.commit('initChatData')
      // this.$store.commit('initGroupData')

      // 注销后，刷新页面
      location.replace(location.href.replace('show=false', 'show=true'))
    },
    async handleLogout2 () {
      this.doScatterLogout()
      this.showLoginBtn = true
    },
    /**
     * 登录处理
     */
    async handleLogin () {
      // 设置登录按钮状态
      this.loginBoxVisible = true
    },
    /**
     * 聊天窗体滚动到底部
     */
    resizeToBottom () {
      this.$refs.scrollWrap.scrollTop = this.$refs.msgWrap.offsetHeight
      this.resetUnreadNums()
      this.isBottom = true

      lazyloadImage({
        wrap: this.$refs.scrollWrap,
        imageArr: this.chatImageArrSel,
        derection: 'up'
      })
    },
    /**
     * @des 点击，查看未读消息
     * 直接滚动到聊天列表底部
     */
    doSetRead () {
      this.resizeToBottom()
    },
    /**
     * 添加表情
     */
    addEmoji (value) {
      this.inputMsg += value
    },
    /**
     * @des 聊天窗体滚动事件处理集
     */
    handleScroll (e) {
      this.enableScroll = true
      e.target.focus()
      // 防止切换房间时触发滚动处理
      if (!this.group.chatList.length) {
        return
      }
      // 防止滚动到置顶消息触发滚动
      // if (this.isScrollToView) {
      //   return
      // }

      let msgWrap = this.$refs.msgWrap
      let totalHeight = msgWrap.offsetHeight
      let scrollTop = e.target.scrollTop
      if (scrollTop === 0 && !this.lockMore) {
        if (this.group.endHash !== null) {
          this.lockMore = true
          this.getHistoryMsg().then((res) => {
            if (res === 'end') {
              this.lockEnd = true
            } else {
              let scrollBottom = totalHeight - scrollTop
              this.$nextTick(() => {
                e.target.scrollTop = msgWrap.offsetHeight - scrollBottom
                this.ps && this.ps.update()
                setTimeout(() => {
                  this.lockMore = false
                }, 800)
              })
            }
          })
        }
      }

      // 滚动到底部清空未读消息状态
      if (scrollTop + e.target.offsetHeight > totalHeight) {
        this.isBottom = true
        if (this.unreadNums) {
          this.resetUnreadNums()
        }
      } else {
        this.isBottom = false
      }

      lazyloadImage({
        wrap: this.$refs.scrollWrap,
        imageArr: this.chatImageArrSel,
        derection: 'up'
      })
    },
    /**
     * @des 处理消息发送
     */
    async handleSend (e) {
      // 判断是否被禁言
      if (this.blockList.some(id => id == this.userId)) {
        Message({
          message: this.$t('chat.youAreBan'),
          type: 'error'
        })
        return
      }
      // 替换emoji字符串
      let _inputMsg = this.inputMsg
      let parts = _inputMsg.match(/\["[a-z0-9A-Z_]+"\]/g)
      for (let k in parts) {
        let emoji = this.emojiMap[parts[k]]
        if (emoji) {
          _inputMsg = _inputMsg.replace(parts[k], emoji)
        }
      }
      let text = _inputMsg.trim()

      if (text.length === 0) {
        Message({
          message: this.$t('chat.cannotBeEmpty'),
          type: 'warning'
        })
        return
      }

      let opt = {
        type: 0,
        msg: text
      }

      // 清空输入框
      this.inputMsg = ''

      // 用户不是第一次发言
      if (this.group.members[this.userId]) {
        let createTime = Date.now()
        this.addChatItem({
          from: this.userId,
          content: text,
          hash: `${createTime}`,
          timestamp: createTime,
          createTime,
          msg_type: '0',
          loading: true
        })
        opt.createTime = createTime

        await this.doSendMsg(opt)
      } else {
        // 发言后，才滚动底部
        await this.doSendMsg(opt)
      }

      // 滚到底部
      this.$nextTick(function () {
        this.resizeToBottom()
      })

      e.preventDefault()
      return false
    },
    placeEnd (el) {
      var range = document.createRange()
      range.selectNodeContents(el)
      range.collapse(false)
      var sel = window.getSelection()
      sel.removeAllRanges()
      sel.addRange(range)
    },
    initDrop (e) {
      e.preventDefault()
      let files = Array.from(e.dataTransfer.files)
      files.forEach(file => this.handleFile(file))
    },
    initDragOver (e) {
      e.preventDefault()
    },
    initPaste (event) {
      var items = (event.clipboardData || window.clipboardData).items
      if (items && items.length) {
        Array.from(items).forEach(item => {
          let file = item.getAsFile()
          if (file) {
            this.handleFile(file)
          }
        })
      }
    },
    /**
     * 文件预处理
     * @return {Object} data 预处理文件信息
     * @param {Number} data.type
     * @param {File} data.res
     */
    async preHandleFile (file) {
      let type = file.type
      let size = file.size
      if (type.match('video')) {
        return size > 3 * 1024 * 1024 ? Promise.reject(new Error(file)) : Promise.resolve({
          type: 2,
          res: file
        })
      } else if (type.match('audio')) {
        return size > 2 * 1024 * 1024 ? Promise.reject(new Error(file)) : Promise.resolve({
          type: 3,
          res: file
        })
      } else if (type.match('image')) {
        let image = await new ImageMin({
          file: file,
          maxSize: 1024 * 1024
        })
        return {
          type: 1,
          preview: image.base64,
          res: image.res
        }
      }
    },
    /**
     * @des 处理文件发送
     */
    async handleFile (e) {
      let inputfile
      if (e.constructor === File) {
        inputfile = e
      } else {
        inputfile = e.target.files[0]
      }
      try {
        let fileInfo = await this.preHandleFile(inputfile)
        let opt = { res: fileInfo.res }

        if (this.group.members[this.userId]) {
          let createTime = Date.now()
          this.addChatItem({
            content: fileInfo.preview || '',
            from: this.userId,
            hash: `${createTime}`,
            msg_type: fileInfo.type,
            timestamp: createTime,
            res: fileInfo.res,
            loading: true,
            createTime
          })
          opt.createTime = createTime
        }

        this.doSendFile(opt)
        this.toolShow = false
        setTimeout(() => {
          this.$refs.toolbar.resetInput()
          this.resizeToBottom()
        }, 100)
      } catch (error) {
        Message({
          message: this.$t('chat.maxUploadTips'),
          type: 'warning'
        })
      }
    },

    /**
     * @des 控制聊天窗口开关
     */
    handleToggleChat (flag) {
      if (flag) {
        this.showChat = true
        this.unreadCounts = 0
        this.$nextTick(() => {
          this.postResize(this.width, this.height + 16)
          this.resizeToBottom()
        })
      } else {
        this.showChat = false
        this.$nextTick(() => {
          this.postResize(56, 50)
        })
      }
    },
    postResize (width, height) {
      let request = {
        action: 'meechat:resize',
        data: {
          ch: height,
          cw: width
        }
      }
      return window.parent.postMessage(request, '*')
    },
    /**
     * @des 引用某条消息
     */
    quoteMsg (msg) {
      this.inputMsg = msg
    },
    /**
     * @des 某条消息被删除
     */
    deleteMsg (hash) {
      this.deleteChatItem(hash)
    },
    pinMsgClose () {
      this.pinMsg.visible = false
    },
    scrollToView () {
      if (!this.pinMsg) return
      let hash = this.pinMsg.hash
      let index = this.group.chatList.findIndex(item => item.hash === hash)

      if (index < 0) {
        this.addPinChatItem(this.pinMsg)
        index = 0
      }

      let node = this.$refs.msgWrap.getElementsByClassName('msg-item')[index]
      let toOffsetTop = index >= 0 ? node.offsetTop - (this.pinMsg ? 40 : 10) : node.offsetTop

      scrollMsgIntoView(
        this.$refs.scrollWrap, toOffsetTop, node
      )

      // 防止加载更多
      this.isScrollToView = true
      setTimeout(() => {
        this.isScrollToView = false
        lazyloadImage({
          wrap: this.$refs.scrollWrap,
          imageArr: this.chatImageArrSel,
          derection: 'up'
        })
      }, 2000)
    },
    scrollToMsg (index) {
      let hash = this.atList[index].hash
      let eleIndex = this.group.chatList.findIndex(item => item.hash === hash)
      if (eleIndex >= 0) {
        let node = this.$refs.msgWrap.querySelectorAll('.msg-item').item(eleIndex)
        scrollMsgIntoView(this.$refs.scrollWrap, node.offsetTop - (this.pinMsg ? 40 : 10), node)
      }
      this.removeAtListLast()
    }
  }
}
