// FlowWSService

const debug = 1
let log = () => {}
if (debug) {
  log = console.log.bind(console.log, '%cSVC:', 'color:#0a0')
}

export default {

  install (Vue, options) {
    let ws
    let connected = false
    let failed

    const eventBus = new Vue()

    let service = {
      /* documentUpdate (nodeData, id) { // Specific
        log('documentUpdate -- ', nodeData)
        if (connected === false) {
          log('Saving failed, rescheduling')
          failed = {
            DocumentUpdate: JSON.parse(JSON.stringify(nodeData)),
            sessId: id
          }
          return
        }
        this.send({op: 'documentUpdate', id: id, data: nodeData})
      }, */
      send (msg) { // Raw message
        ws.send(JSON.stringify(msg))
      },
      // Calls callback if already connected or waits for connection
      connected (cb) {
        if (connected === false) {
          eventBus.$on('open', cb)
          return
        }
        cb()
      },
      // event related
      on: eventBus.$on.bind(eventBus),
      once: eventBus.$once.bind(eventBus),
      off: eventBus.$off.bind(eventBus)
    };

    /// ///////////////
    // Service entry points map
    //
    [
      'sessionNew', 'sessionLoad', // SESSION
      'documentUpdate', 'documentRun',
      'chatEvent', 'chatJoin', 'chatRename', // CHAT
      'linkAdd', 'linkUpdate', 'linkRemove', // LINK
      'nodeUpdate', 'nodeAdd', 'nodeRemove', 'nodeProcess' // NODE
    ].forEach(ftyp => {
      service[ftyp] = (param, id) => {
        log('sending:', ftyp, ' -- ', param)
        if (connected) {
          service.send({op: ftyp, id: id, data: param})
          return
        }
        if (ftyp !== 'documentUpdate') return // Do not persist other than documentUpdate on reconnection
        // Schedule when is connected
        service.once('open', () => {
          service.send({op: ftyp, id: id, data: param})
        })
      }
    })

    // WS Connector
    const connect = (loc) => {
      ws = new window.WebSocket(loc)
      ws.onopen = () => {
        log('connected')
        connected = true
        eventBus.$emit('open')
        if (failed) {
          log('Persisting failed document (retry)')
          service.documentUpdate(failed.DocumentUpdate, failed.sessId)
        }
      }
      ws.onmessage = (e) => { // receiving message
        log('received:', e.data)
        const msg = JSON.parse(e.data)
        eventBus.$emit(msg.op, msg) // Pass message through
      }
      ws.onerror = (e) => { connected = false }
      ws.onclose = (e) => {
        log('Lost connection', e)
        if (connected === true) {
          eventBus.$emit('close')
        } // emit close
        connected = false
        setTimeout(() => connect(loc), 3000) // Reconnect
      }
    }

    connect(options.location)

    Vue.prototype.$flowService = service
  }

}
