import { mapActions, mapState, mapMutations } from 'vuex'
import { scrollMsgIntoView, lazyloadImage, getMeechatType } from '@/util/util.js'
import { emojiList } from '@/util/emoji'
import { Message } from 'element-ui'
import WsManager from '@/util/wsManager.js'
import ImageMin from '@/util/imageMin.js'
import { getMiniWsUrl } from '@/util/contract.js'
import PostMessager from '@/util/postMessager.js'

// 聊天mixin 用于chatRoom组件
export const chatMixin = {
  watch: {
    '$route' () {
      this.bdHiden = true
      // 切换房间
      this.groupSet = false
      this.lockMore = false
      this.lockEnd = false
      this.enableScroll = false

      if (this.meechatType == 'mini') this.initMiniRoom()
      else this.initRoom()
    },
    chatList (val) {
      let lastVal = val[val.length - 1]
      if ((lastVal && lastVal.msg_type == 4) || this.isBottom) {
        // 自己发的红包自动滚动到底部
        this.$nextTick(this.resizeToBottom)
      }
    },
    isJoinGroup (val) {
      if (val == 1) setTimeout(this.resizeToBottom.bind(this), 100)
    }
  },
  data () {
    return {
      isLoadingRoom: true,
      groupSet: false,
      lockMore: false,
      lockEnd: false,
      enableScroll: false, // 记录滚动条是否激活的状态
      isBottom: true,
      scrollHeight: 100, // 滚动条高度
      isScrollToView: false,
      isShowGroudMgr: false, // 是否显示群管理
      chatImageArrSel: null, // 图片组
      meechatType: getMeechatType()
    }
  },
  computed: {
    ...mapState(['curSession', 'group', 'chat', 'userId', 'userInfo']),
    ...mapState({
      creator: state => state.group.creator,
      isJoin: state => state.group.isJoin,
      pinMsg: state => state.group.pinMsg,
      atList: state => state.group.atList,
      unreadNums: state => state.group.unreadNums,
      chatList: state => state.group.chatList,
      members: state => state.group.members,
      sessionId: state => state.curSession,
      sessionInfo: state => state.group.sessionInfo
    }),
    isExist () {
      // 是否存在在会话列表中
      let sessionList = this.chat.sessionList
      if (sessionList && sessionList.length) {
        return sessionList.some(e => {
          return e.session_id == this.sessionId
        })
      } else {
        return true
      }
    },
    isAdmin () {
      return (this.group.adminList && this.group.adminList.some(id => id == this.userId)) || this.group.creator == this.userId
    },
    isPrivate () {
      return this.$store.getters.isPrivate
    },
    isCreator () {
      return this.userId == this.creator
    },
    isJoinGroup () {
      if (this.group && this.group.groupId) {
        return this.isJoin ? 1 : 0
      } else {
        return 1
      }
    },
    linkToCreator () {
      let { creator, userId } = this.group
      let sessionId = creator > userId ? `${userId}-${creator}` : `${creator}-${userId}`
      return `${location.origin}/#/pm/${sessionId}`
    }
  },
  mounted () {
    if (this.meechatType == 'mini') this.initMiniRoom()
    else this.initRoom()

    document.getElementById('app').addEventListener('contextmenu', e => e.preventDefault())
    this.chatImageArrSel = this.$refs.scrollWrap.getElementsByTagName('img')

    // this.$nextTick(() => {
    //   this.$refs.msgWrap.style.height = 'auto'
    // })
  },
  methods: {
    ...mapMutations([
      'initGroup',
      'setUserId',
      'setToken',
      'resetUnreadNums',
      'addChatItem',
      'deleteChatItem',
      'initState',
      'clearAtList',
      'clearHash',
      'setSessionItemUnread',
      'clearChatList',
      'changeSessionId',
      'addPinChatItem'
    ]),
    ...mapActions([
      'setAccount',
      'getGroupInfo',
      'getUserInfo',
      'getNewMsgFromDb',
      'getNewMsg',
      'getHistoryMsg',
      'doSendMsg',
      'getPrivateNewMsgFromDb',
      'getPrivateNewMsg',
      'getPrivateHistoryMsg',
      'doSendPrivateMsg'
    ]),
    /**
     * 内嵌房间初始化
    */
    async initMiniRoom () {
      // 初始化postMessage消息管理器
      let callback = (event) => {
        if (event.action === 'meechat:setShow') {
          this.handleToggleChat(event.show)
        } else if (event.action === 'meechat:logout') {
          this.handleLogout2()
        }
      }

      this.postMessager = new PostMessager('*', { callback })
      window.postMessager = this.postMessager

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

      // 检查登录态
      let userId = localStorage.getItem('user_id')
      let token = localStorage.getItem('token')
      let account = localStorage.getItem('account')
      if (userId && token && account) {
        this.setUserId(userId)
        this.setToken(token)
        this.setAccount(JSON.parse(account))
        this.showLoginBtn = false
        if (self === top) {
          await this.scatterConnect()
        }
        await this.getUserInfo()
      }

      this.$nextTick(this.initChat)

      this.$nextTick(this.initMiniSocket)
    },
    async initRoom () {
      if (!this.userInfo) {
        await this.getUserInfo()
      }

      if (!this.userInfo) return
      this.changeSessionId(this.$route.params.id)
      this.clearHash()
      this.clearChatList()
      this.initState()

      if (this.isExist) {
        // 把会话列表的消息数设置为0
        this.$store.commit('setSessionItemUnread', {
          session_id: this.curSession,
          unread: 0,
          curSession: this.curSession
        })
      }

      if (this.isPrivate) await this.initPersonChat()
      else await this.initGroupChat()
    },
    /**
     * @des 私聊初始化处理
     */
    async initPersonChat () {
      let flag = await this.getPrivateNewMsgFromDb()
      if (!flag) {
        // 如果indexDB没数据时，才需要loading
        this.showLoadingRoom(true)
      }

      let data = await this.getPrivateNewMsg()
      this.showLoadingRoom(false)

      this.$nextTick(() => {
        this.resizeToBottom()
        this.bdHiden = false
      })

      setTimeout(() => {
        // 不存在会话，则添加会话
        if (!this.isExist) {
          // 获取对方信息
          let otherInfo = null
          for (let key in data.data.userMap) {
            if (key != this.userId) {
              otherInfo = data.data.userMap[key]
            }
          }

          if (otherInfo) {
            let obj = {
              cover_photo: otherInfo.cover_photo,
              is_group: '0',
              name: otherInfo.nick_name,
              session_id: this.sessionId
            }
            this.$store.commit('addSessionItem', obj)
          }
        }
      }, 1000)

      return data
    },
    /**
     * @des 聊天群初始化处理
     */
    async initGroupChat () {
      this.initGroup({
        userId: this.userId,
        groupId: this.sessionId,
        useCache: false
      })
      this.isShowGroudMgr = false

      this.getGroupInfo()

      let flag = await this.getNewMsgFromDb()
      if (!flag) {
        // 如果indexDB没数据时，才需要loading
        this.showLoadingRoom(true)
      }

      await this.getNewMsg()
      this.showLoadingRoom(false)

      this.$nextTick(() => {
        this.resizeToBottom()
        this.bdHiden = false

        lazyloadImage({
          wrap: this.$refs.scrollWrap,
          imageArr: this.chatImageArrSel,
          derection: 'up'
        })
      })

      setTimeout(() => {
        // 不存在会话，则添加会话
        if (!this.isExist) {
          // 获取对方信息
          if (this.group) {
            let obj = {
              cover_photo: this.group.coverPhoto,
              is_group: '1',
              name: this.group.groupName,
              session_id: this.sessionId
            }
            this.$store.commit('addSessionItem', obj)
          }
        }
      }, 1000)
    },
    // Mini链接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)
            }
          }
        }
      })
    },
    /**
     * @des 滚动事件监听
     */
    initScrollEvent () {},
    /**
     * @des 聊天窗体滚动事件处理集
     */
    async handleScroll (e) {
      // 防止切换房间时触发滚动处理
      if (!this.group.chatList.length) {
        return
      }
      // 防止滚动到置顶消息触发滚动
      // if (this.isScrollToView) {
      //   return
      // }

      // 激活滚动条
      this.enableScroll = true
      let totalHeight = this.$refs.msgWrap.offsetHeight - 16
      let scrollTop = e.target.scrollTop

      // 差不多滚动到顶部
      if (scrollTop == 0 && !this.lockMore) {
        if (this.group.endHash !== null) {
          this.lockMore = true
          let res
          if (this.isPrivate) {
            res = await this.getPrivateHistoryMsg()
          } else {
            res = await this.getHistoryMsg()
          }
          if (res === 'end') {
            this.lockEnd = true
          } else {
            let scrollBottom = totalHeight - scrollTop
            this.$nextTick(() => {
              e.target.scrollTop =
                this.$refs.msgWrap.offsetHeight - scrollBottom
              setTimeout(() => {
                this.lockMore = false
              }, 800)
            })
          }
        }
      }

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

      lazyloadImage({
        wrap: this.$refs.scrollWrap,
        imageArr: this.chatImageArrSel,
        derection: 'up'
      })
    },
    /**
     * @des 聊天窗体滚动到底部
     */
    resizeToBottom () {
      if (!this.$refs.msgWrap) return
      this.$refs.msgWrap.style.height = 'auto'
      this.$refs.scrollWrap.scrollTop = this.$refs.msgWrap.offsetHeight
      this.resetUnreadNums()

      lazyloadImage({
        wrap: this.$refs.scrollWrap,
        imageArr: this.chatImageArrSel,
        derection: 'up'
      }, 200)
    },
    /**
     * @des 点击，查看未读消息
     * 直接滚动到聊天列表底部
     */
    doSetRead () {
      this.resizeToBottom()
    },
    /**
     * @des 引用某条消息
     */
    quoteMsg (msg) {
      this.$refs.inputArea.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 : node.offsetTop

      let lazy = function () {
        lazyloadImage({
          wrap: this.$refs.scrollWrap,
          imageArr: this.chatImageArrSel,
          derection: 'up'
        })
      }
      scrollMsgIntoView(
        this.$refs.scrollWrap, toOffsetTop, node, lazy.bind(this)
      )
      // 防止加载更多
      this.isScrollToView = true
      setTimeout(() => {
        this.isScrollToView = false
      }, 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.getElementsByClassName('msg-item').item(eleIndex)
        scrollMsgIntoView(
          this.$refs.scrollWrap,
          node.offsetTop - (this.pinMsg ? 40 : 10),
          node
        )
      }
      this.clearAtList()
    },
    async joinGroup () {
      this.showLoadingRoom(true)
      await this.$store.dispatch('joinGroup')
      this.showLoadingRoom(false)
    },
    // 群管理
    showGroudMgr (flag) {
      this.isShowGroudMgr = flag == 1
    },
    // 关闭表情,文件栏
    initEmojiAndTool () {
      this.emojiShow = false
      this.toolShow = false
    },
    showLoadingRoom (flag) {
      this.isLoadingRoom = flag
    }
  },
  beforeDestroy () {
    document.body.removeEventListener('click', this.initEmojiAndTool)
  }
}

// 聊天输入框mixin
export const inputMixin = {
  computed: {
    ...mapState(['group', 'userId']),
    ...mapState({
      chatInputFocus: state => state.group.chatInputFocus,
      blockList: state => state.group.blockList
    }),
    isPrivate () {
      return this.$store.getters.isPrivate
    },
    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
    }
  },
  data () {
    return {
      filePreviewShow: false, // 是否显示文件预览
      emojiShow: false, // 是否显示emoji
      fileInfo: null, // 当前上传文件
      inputMsg: '',
      atInd: 0,
      meechatType: getMeechatType()
    }
  },
  mounted () {
  },
  methods: {
    ...mapMutations(['updateChatInputFocus', 'addChatItem']),
    ...mapActions(['doSendMsg', 'doSendFile', 'doSendPrivateMsg']),
    addEmoji (val) {
      this.inputMsg += val
      this.emojiShow = false
      this.$refs.chatInput.focus()
    },
    closeFilePreview () {
      this.fileInfo = null
      this.filePreviewShow = false
      this.emptyFileForm()
    },
    showFilePreview (fileInfo) {
      if (!fileInfo) return

      this.fileInfo = fileInfo
      this.filePreviewShow = true
    },
    /**
     * @des 处理消息发送
     */
    handleInput () {
      this.inputMsg = this.inputMsg.substring(0, 5000)
    },
    /**
     * @des 处理消息发送
     */
    async handleSend (e) {
      // 判断是否被禁言
      if (this.blockList.some(id => id == this.userId)) {
        Message({
          message: '您已被禁言',
          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().substring(0, 5000)

      if (text.length === 0) {
        Message({
          message: '聊天内容不能为空',
          type: 'warning'
        })
        return
      }

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

      // 用户不是第一次发言
      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
      }

      this.inputMsg = ''

      let data = this.isPrivate ? await this.doSendPrivateMsg(opt) : await this.doSendMsg(opt)
      // // 发送成功后，才加
      this.$store.commit('setSessionItemUnread', {
        session_id: this.curSession,
        unread: 0,
        curSession: this.curSession,
        cont: text,
        timestamp: data.timestamp
      })

      // 滚到底部
      this.$nextTick(function () {
        this.resizeToBottom ? this.resizeToBottom() : this.$emit('toBottom')

        lazyloadImage({
          wrap: this.$refs.scrollWrap,
          imageArr: this.chatImageArrSel,
          derection: 'up'
        })
      })

      e.preventDefault()
      return false
    },
    /**
     * 文件预处理
     * @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,
            preview: window.webkitURL.createObjectURL(file)
          })
      } else if (type.match('audio')) {
        return size > 2 * 1024 * 1024
          ? Promise.reject(new Error(file))
          : Promise.resolve({
            type: 3,
            res: file,
            preview: window.webkitURL.createObjectURL(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)

        if (this.meechatType == 'pc') this.showFilePreview(fileInfo)
        else this.handleFileSend(fileInfo)
      } catch (error) {
        Message({
          message: '上传文件大小限制：音频2M以内，视频3M以内',
          type: 'warning'
        })
      }
    },
    // 发送文件消息
    handleFileSend (fileInfo) {
      this.filePreviewShow = false

      let opt = { res: fileInfo.res }
      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)
      setTimeout(() => {
        this.emptyFileForm()
        this.$refs.toolbar && this.$refs.toolbar.resetInput()
        this.resizeToBottom ? this.resizeToBottom() : this.$emit('toBottom')
      }, 100)
    },
    // 初始文件表单
    emptyFileForm () {
      if (this.$refs.inputFile) {
        this.$refs.inputFile.value = null
      }
      if (this.$refs.inputFile1) {
        this.$refs.inputFile1.value = null
      }
      if (this.$refs.inputFile2) {
        this.$refs.inputFile2.value = null
      }
      if (this.$refs.inputFile3) {
        this.$refs.inputFile3.value = null
      }
    }
  }
}
