/**
 * 心跳开始结束的时机修改前的 备份
 */
import { Message, MessageBox } from 'element-ui'
import store from '@/store'
import router from '@/router'

let ws // websocket 实例
let cls = 0
let lockReconnect = false // 避免重复连接
let websocktTimer // 定时器
let wsUrl = null
// const wsUrl = 'ws://' + process.env.SOCKET_IP + ':' + process.env.SOCKET_PORT

// 创建scoket连接
export function createWebSocket() {
  wsUrl = 'ws://' + store.getters.serverConfig.SOCKET_IP + ':' + store.getters.serverConfig.SOCKET_PORT
  try {
    if ('WebSocket' in window) {
      ws = new WebSocket(wsUrl)
      init()
    } else {
      Message.error('当前浏览器不支持Websocket!')
    }
  } catch (e) {
    reconnect(wsUrl)
  }
}

// 连接
function init() {
  ws.onopen = function() {
    // console.groupCollapsed(`telWebsocket:`)
    console.log(new Date() + '  telWebsocket  ' + '建立连接：' + wsUrl)
    // 心跳检测重置
    heartCheck.reset().start()
    cls = 0
    // 修改store 中连接状态
    store.dispatch('ConnectWs', true)
    // 修改 store 中telwebsocket的数据
    store.dispatch('ChangeTelWSMsg', {
      'wsUrl': wsUrl,
      'operationType': '建立连接'
    })
  }

  // 接收到消息的回调方法
  ws.onmessage = function(evt) {
    // 如果获取到消息，心跳检测重置
    // 拿到任何消息都说明当前连接是正常的
    heartCheck.reset().start()
    console.log('%c' + new Date() + '%c receive%c telWebsocket %ctype:' + JSON.parse(evt.data)[0].Type + '%c ' + evt.data, 'color: #111', 'color: #67C23A', 'color: #111', 'color: #67C23A', 'color: #111')
    dealMsg(JSON.parse(evt.data)[0])
    // 修改 store 中telwebsocket的数据
    const telWSData = JSON.parse(evt.data)[0]
    telWSData.operationType = '接收'
    store.dispatch('ChangeTelWSMsg', telWSData)
  }

  // 连接关闭的回调方法
  ws.onclose = function(evt) {
    if (cls === 0) {
      cls = 1
      console.log('telWebsocket连接关闭')
      // console.groupEnd()
      // 修改store 中连接状态
      store.dispatch('ConnectWs', false)
      store.dispatch('ChangeLineState', 1)
      // 修改 store 中telwebsocket的数据
      store.dispatch('ChangeTelWSMsg', {
        'wsUrl': wsUrl,
        'operationType': '连接关闭'
      })
      reconnect(wsUrl)
    }
  }

  // 连接发生错误的回调方法
  ws.onerror = function(evt) {
    // 产生异常
    console.warn('telWebsocket连接出现异常！')
    // 修改 store 中telwebsocket的数据
    store.dispatch('ChangeTelWSMsg', {
      'wsUrl': wsUrl,
      'operationType': '连接异常'
    })
    if (ws == null || ws.readyState !== ws.OPEN) {
      console.log(new Date() + 'telWebsocket开始重连')
      // 修改 store 中telwebsocket的数据
      store.dispatch('ChangeTelWSMsg', {
        'wsUrl': wsUrl,
        'operationType': '开始重连'
      })
      reconnect(wsUrl)
    }
  }
}

/**
 * 重新连接
 * @ url telWebsocket 链接
 */
function reconnect(url) {
  if (lockReconnect) return
  lockReconnect = true
  // 没连接上会一直重连，设置延迟避免请求过多
  websocktTimer && clearTimeout(websocktTimer)
  websocktTimer = setTimeout(function() {
    console.log(new Date() + '    ' + 'telWebsocket重连中……')
    // 修改 store 中telwebsocket的数据
    store.dispatch('ChangeTelWSMsg', {
      'wsUrl': wsUrl,
      'operationType': '重连中……'
    })
    createWebSocket(url)
    lockReconnect = false
  }, 2000)
}

/**
 * 发送
 * @ socketDatas 发送的数据 type {}
 */
export function Send(scoketDatas) {
  if (ws.readyState !== ws.OPEN) {
    reconnect(wsUrl)
  }
  if (ws.readyState === ws.OPEN) {
    console.log('%c' + new Date() + '%c  send %c telWebsocket  ' + JSON.stringify(scoketDatas), 'color: #111', 'color: #409EFF', 'color: #111')
    ws.send(JSON.stringify(scoketDatas))
    scoketDatas.operationType = '发送'
    // 修改 store 中telwebsocket的数据
    store.dispatch('ChangeTelWSMsg', scoketDatas)
  }
}

// 心跳检测
const heartCheck = {
  timeout: 25000, // 25秒
  timeoutObj: null,
  serverTimeoutObj: null,
  reset: function() {
    clearTimeout(this.timeoutObj)
    clearTimeout(this.serverTimeoutObj)
    return this
  },
  start: function() {
    const _self = this
    this.timeoutObj = setTimeout(function() {
      // 这里发送一个心跳，后端收到后，返回一个心跳消息，
      // onmessage拿到返回的心跳就说明连接正常
      const scoketDatas = {
        'Type': 'Heart',
        'AgentExten': store.getters.extension, // 分机号
        'AgentGroup': store.getters.groupid // 坐席组id
      }
      Send(scoketDatas)
      _self.serverTimeoutObj = setTimeout(function() { // 如果超过一定时间还没重置，说明后端主动断开了
        ws.close() // 如果onclose会执行reconnect，我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
      }, _self.timeout)
    }, this.timeout)
  }
}

/**
 * 处理接收的消息
 * @ msgData 接收的数据 type {}
 */
function dealMsg(msgData) {
  if (msgData) {
    const rlt = msgData.Result
    if (rlt === true) {
      switch (msgData.Type.toLowerCase()) {
        case 'login': // 签入
          LoginBack()
          break
        case 'logout': // 签出
          LogoutBack()
          break
        case 'dropcall': // 挂断
          DropCallBack()
          break
        case 'makecall': // 外呼
          MakeCallBack()
          break
        case 'setstate': // 置忙置闲
          SetState(msgData)
          break
        case 'meeting': // 多方通话
          MeetingBack()
          break
        case 'transfer': // 转移
          TransferBack()
          break
        case 'consult': // 协商呼叫
          ConsultBack()
          break
        case 'hold': // 保持
          HoldBack()
          break
        case 'retrieve': // 接回
          RetrieveBack()
          break
        case 'incoming': // 来电
          IncomingBack(msgData)
          break
        case 'linestateagent': // 线路状态通知
          LineStateAgentBack(msgData)
          break
        case 'recordpath': // 录音返回
          RecordPathBack(msgData)
          break

        case 'listen':
          updateSeatMonitorlists() // 更新坐席监控内坐席的状态
          Message.success('监听操作成功！')
          break
        case 'forceagentstate':
          updateSeatMonitorlists() // 更新坐席监控内坐席的状态
          Message.success('置闲操作成功！')
          break
        case 'replace':
          updateSeatMonitorlists() // 更新坐席监控内坐席的状态
          Message.success('代接操作成功！')
          break
        case 'insert':
          updateSeatMonitorlists() // 更新坐席监控内坐席的状态
          Message.success('强插操作成功！')
          break
        case 'intercept':
          updateSeatMonitorlists() // 更新坐席监控内坐席的状态
          Message.success('拦截操作成功！')
          break
        case 'cut':
          updateSeatMonitorlists() // 更新坐席监控内坐席的状态
          Message.success('强拆操作成功！')
          break
      }
    } else {
      if (rlt === false) {
        const errCode = msgData.Error % 10000
        const errTips = getErrTips(errCode) // 获取错误信息
        console.error(`telWebsocket错误信息: ${errTips}(errorCode:${errCode})!`)
        Message.error(`telWebsocket错误信息: ${errTips} !`)
      } else {
        console.error(`telWebsocket错误信息: ${rlt} !`)
        Message.error(`telWebsocket错误信息: ${rlt} !`)
      }
    }
  }
}

/**
 * 获取 错误信息
 * @ errCode 错误代码
 */
function getErrTips(errCode) {
  let errTips = ''
  switch (errCode) {
    case 9011:
      errTips = '分机号不存在'
      break
    case 9012:
      errTips = '分机号已绑定'
      break
    case 9013:
      errTips = '坐席已登陆'
      break
    case 9058:
      errTips = '授权验证失败'
      break
    case 10:
      errTips = '没有找到线路'
      break
    case 11:
      errTips = '线路忙'
      break
    case 12:
      errTips = '线路非空闲'
      break
    case 13:
      errTips = '线路非振铃'
      break
    case 14:
      errTips = '非通话'
      break
    case 15:
      errTips = '线路空闲'
      break
    case 16:
      errTips = '线路已邦定任务'
      break
    case 50:
      errTips = '对端线路空'
      break
    case 51:
      errTips = '对端线路忙'
      break
    case 52:
      errTips = '非分机'
      break
    case 20:
      errTips = '没找到座席'
      break
    case 21:
      errTips = '坐席绑定异常'
      break
    case 22:
      errTips = '坐席非空闲'
      break
    case 30:
      errTips = '被监控中'
      break
    case 31:
      errTips = '错误指令'
      break
    case 100:
      errTips = '线路关联任务失败'
      break
    case 101:
      errTips = '执行操作失败'
      break
    case 102:
      errTips = '呼叫取消'
      break
    case 103:
      errTips = '挂机失败'
      break
    case 104:
      errTips = '禁止自呼'
      break
    case 110:
      errTips = '不是保持状态'
      break
    case 111:
      errTips = '不在放音'
      break
    case 250:
      errTips = '正常挂机'
      break
    case 251:
      errTips = '用户忙'
      break
    case 252:
      errTips = '未接听'
      break
    case 253:
      errTips = '没响应'
      break
    case 254:
      errTips = '拒接'
      break
    case 255:
      errTips = '未注册'
      break
    case 259:
      errTips = '未知'
      break
    default:
      errTips = errCode
      break
  }
  return errTips
}

// 签入
function LoginBack() {
  store.dispatch('LoginWs', true)
  store.dispatch('ChangeTopRightState', ['空闲', true])
  // 弹出任务信息
  store.dispatch('ChangeTask', true)
}

// 签出
function LogoutBack() {
  store.dispatch('LogoutWs', false)
  store.dispatch('ChangeTopRightState', ['已签出', false])
  // 重置初始化状态
  resetInitState()
}

// 重置初始化状态
function resetInitState() {
  store.dispatch('ChangeSeatState', 2) // 坐席状态（空闲）
  store.dispatch('ChangeLineState', 1) // 线路状态（空闲）
  store.dispatch('ChangeCallNum', '') // 顶部电话号码（''）
  store.dispatch('ChangeCallType', 'MakeCall') // 发送的通话类型（默认是外呼）
  store.dispatch('ChangeTask', false) // 外呼任务信息是否显示
  store.dispatch('ChangeTaskFirst', true) // 外呼任务信息是否是第一次弹出
}

/**
 * 置忙置闲
 * sayOption (点击置忙置闲后的返回值)
 * */
function SetState(sayOption) {
  store.dispatch('ChangeSeatState', sayOption.State)
  if (sayOption.State === 5) {
    store.dispatch('ChangeTopRightState', ['忙碌', false])
  }
  if (sayOption.State === 2) {
    store.dispatch('ChangeTopRightState', ['空闲', true])
  }
}

// 线路状态通知
function LineStateAgentBack(linedata) {
  // 0分机不可用，1空闲，2摘机等待拨号，3正在拨号，4呼出振铃，5来电振铃，6通话中，7播放忙音中，8移除IP分机，10通话保持中
  store.dispatch('ChangeLineState', linedata.State)
  switch (linedata.State) {
    case 0:
      store.dispatch('ChangeTopRightState', ['分机不可用', false])
      break
    case 1:
      store.dispatch('ChangeTopRightState', ['空闲', true])
      break
    case 2:
      store.dispatch('ChangeTopRightState', ['摘机等待拨号', true])
      break
    case 3:
      store.dispatch('ChangeTopRightState', ['正在拨号', true])
      break
    case 4:
      store.dispatch('ChangeTopRightState', ['呼出振铃', true])
      break
    case 5:
      store.dispatch('ChangeTopRightState', ['来电振铃', true])
      break
    case 6:
      store.dispatch('ChangeTopRightState', ['通话中', true])
      break
    case 7:
      store.dispatch('ChangeTopRightState', ['播放忙音中', true])
      break
    case 8:
      store.dispatch('ChangeTopRightState', ['移除IP分机', false])
      break
    case 10:
      store.dispatch('ChangeTopRightState', ['通话保持中', true])
      break
    default:
      break
  }
}

// 协商呼叫
function ConsultBack() {
  // console.log('.....协商呼叫成功！....')
  MessageBox.confirm('请您确认转移或者挂机?', ' ', {
    confirmButtonText: '转移',
    cancelButtonText: '挂机',
    type: 'warning'
  }).then(() => {
    Send({
      'Type': 'ConfirmTransfer',
      'AgentID': store.getters.usercode, // 工号号
      'AgentExten': store.getters.extension, // 分机号
      'EndParmer': '1' // 1.转移 3.将对方挂断
    })
    Message.success('转移成功!')
    store.dispatch('ChangeCallNum', '') // 顶部电话号码（''）
    store.dispatch('ChangeCallType', 'MakeCall') // 发送的通话类型（默认是外呼）
  }).catch(() => {
    Send({
      'Type': 'ConfirmTransfer',
      'AgentID': store.getters.usercode, // 工号
      'AgentExten': store.getters.extension, // 分机号
      'EndParmer': '3' // 1.转移 3.将对方挂断
    })
    Message.success('挂机成功!')
  })
}

// 来电
function IncomingBack(inComingData) {
  const inComingNumber = inComingData.Number
  const inComingCallId = inComingData.CallID
  store.dispatch('ChangeCallNum', inComingNumber)
  // 组id和groupid一致是正常弹屏；不一致是预测外呼弹屏；
  if (inComingData.TaskIcon === store.getters.groupid) {
    // 来电弹屏 TaskIcon 的值是坐席组id
    router.push({ name: 'callScreen', params: { callid: inComingCallId, telInNumber: inComingNumber }})
  // router.push({ name: 'autoCallScreen', params: { callid: inComingCallId, telInNumber: inComingNumber }})
  // router.push({ path: '/callScreen', query: { callid: inComingCallId, telInNumber: inComingNumber}})
  } else {
    // 自动外呼弹屏 TaskIcon值是任务id
    router.push({ name: 'autoCallScreen', params: { callid: inComingCallId, telInNumber: inComingNumber, taskId: inComingData.TaskIcon }})
  }
}

// 挂断
function DropCallBack() {
  store.dispatch('ChangeCallNum', '') // 顶部电话号码（''）
  store.dispatch('ChangeCallType', 'MakeCall') // 发送的通话类型（默认是外呼）
  // 当前在坐席监控中需要 更新坐席监控内坐席的状态
  const curentViews = store.state.tagsView.visitedViews
  for (let i = 0, len = curentViews.length; i < len; i++) {
    if (curentViews[i].name === 'seatMonitor') {
      updateSeatMonitorlists()
      return
    }
  }
}

// 转接
function TransferBack() {
  store.dispatch('ChangeCallNum', '') // 顶部电话号码（''）
  store.dispatch('ChangeCallType', 'MakeCall') // 发送的通话类型（默认是外呼）
}

// 外呼
function MakeCallBack() {}

// 多方通话
function MeetingBack() {}

// 录音返回
function RecordPathBack() {}

// 保持
function HoldBack() { }

// 接回
function RetrieveBack() {}

// 更新坐席监控内坐席的状态
function updateSeatMonitorlists() {
  store.dispatch('ChangeMonitor', true) // 修改监听操作的返回值
}
