import Cable from 'es6-actioncable'
import {make_websocket_path, DEV} from 'common/constants'
import moment from 'common/moment'
import request from 'common/request'
import {set_count, array_from_set} from 'common/utilities'

class Websocket {
  constructor(websocket_params) {
    this.consumer = Cable.createConsumer(make_websocket_path(websocket_params))
    DEV && console.log(`connection succeeded ${moment().format()}`)
  }

  get_consumer() {
    if (!this.consumer) {
      this.connect()
    }
    return this.consumer
  }

  close_connection() {
    if (this.consumer) {
      Cable.endConsumer(this.consumer)
    }
    delete this.consumer
  }
}

let websocket

export function init_websocket(websocket_params) {
  websocket = new Websocket(websocket_params)
}

export default class Channel {
  constructor(channel_name, params) {
    this.registered_events = {}
    this.store_actions = {}
    this.destroy_actions = {}
    this.waiting = {}
    this.channel_name = `${channel_name}Channel`

    this.subscription = websocket.get_consumer().subscriptions.create({channel: this.channel_name, ...params}, {
      connected: () => {
        DEV && console.log(`connected to ${this.channel_name}`)
      },
      received: ({event, action, model, url, object, id}) => {
        if (event) {
          DEV && console.info(event, object)
          const callback = this.registered_events[event]
          callback && callback(object)
        } else if (action == 'store') {
          DEV && console.info(action, model, url)
          if (!this.waiting[model]) {
            this.waiting[model] = {}
          }
          if (set_count(this.waiting[model]) == 0) {
            setTimeout(() => {
              const callback = this.store_actions[model]
              callback && Promise.all(
                array_from_set(this.waiting[model]).map((url) => request.get(url))
              ).then(callback)
              this.waiting[model] = {}
            }, 500)
          }
          this.waiting[model][url] = true
        } else if (action == 'destroy') {
          DEV && console.info(action, model, id)
          const callback = this.destroy_actions[model]
          callback && callback(id)
        }
      }
    })
  }

  register(event, callback) {
    this.registered_events[event] = callback
  }

  register_store(model, callback) {
    this.store_actions[model] = callback
  }

  register_destroy(model, callback) {
    this.destroy_actions[model] = callback
  }

  unsubscribe() {
    if (this.subscription) {
      this.subscription.unsubscribe()
    }
  }
}
