import Taro from '@tarojs/taro'

export default function IMSDK() {
  const STATE = {
    CONNECTING: 0,
    OPEN: 1,
    CLOSING: 2,
    CLOSED: 3,
  }

  const noop = () => []

  const instanceRef = {
    current: undefined,
    onOpen: noop,
    onMessage: noop,
    onError: noop,
    onClose: noop
  }

  const paramsRef = {
    current: {}
  }

  let connected = false

  return {
    STATE,
    getState,
    connect,
    listen,
    send,
  }

  function getState() {
    if (instanceRef.current) {
      return instanceRef.current.readyState
    }

    return STATE.CLOSED
  }

  function listen(name, fns) {
    if (typeof fns === 'function') {
      instanceRef[name] = fns
    }
  }

  function connect(options) {
    Object.assign(paramsRef.current, options || {})
    
    if (instanceRef.current && instanceRef.current.readyState <= STATE.CLOSING) {
      return Promise.resolve()
    }

    return new Promise((resolve, reject) => {
      Taro.connectSocket({
        ...paramsRef.current,
        fail: (err) => reject(err),
      }).then((task) => {
        console.log(`[${now()}]`, '[WS] [connect]', task)
        instanceRef.current = task

        task.onOpen(function () {
          console.log(`[${now()}]`, '[WS] [onOpen]', paramsRef.current)
          resolve()
        })

        task.onMessage(function (msg) {
          console.info(`[${now()}]`, '[WS] [onMessage]', msg)
          instanceRef.onMessage().forEach((f) => f(msg.data))
        })

        task.onError(function (error) {
          console.error(`[${now()}]`, '[WS] [onError]', error)
          instanceRef.onError().forEach((f) => f(error))
        })

        task.onClose(function (res) {
          console.warn(`[${now()}]`, '[WS] [onClose]', res)
          instanceRef.onClose().forEach((f) => f(res))
        })
      })
    })
  }

  function send(data) {
    console.log(`[${now()}]`, '[WS] [SEND]', data)
    return new Promise((resovle, reject) => {
      if (instanceRef.current) {
        instanceRef.current.send({
          data,
          success: resovle,
          fail: (err) => {
            console.error(`[${now()}]`, '[WS] [SEND]', err)
            reject(err)
          },
        })
      } else {
        reject(STATE.CLOSED)
      }
    })
  }

  function now() {
    const dt = new Date()
    const year = dt.getFullYear()
    const month = dt.getMonth() + 1
    const day = dt.getDate()
    const hour = dt.getHours()
    const minutes = dt.getMinutes()
    const seconds = dt.getSeconds()

    const formate = n => n >= 10 ? n : `0${n}`

    return `${year}-${formate(month)}-${formate(day)} ${formate(hour)}:${formate(minutes)}:${formate(seconds)}`
  }
}
