import Echo from 'laravel-echo'
import io from 'socket.io-client'
import { SocketIoPrivateChannel } from 'laravel-echo/dist/channel'
import Config from '../types/Config'
import { NotificationEvent } from '../types/NotificationEvent'

type NewNotificationCb = (payload: { notification: NotificationEvent }) => void
type CloseNotificationCb = (payload: {
  notification: NotificationEvent
}) => void
type CloseNotificationsCb = () => void

enum Events {
  New = 'NewNotification',
  Close = 'CloseNotification',
  CloseAll = 'CloseAllNotifications',
}

window.io = io

class NotificationWebsocketService {
  client!: Echo
  clientUid!: string
  projectId!: string

  init(params: {
    authToken: string
    clientUid: string
    projectId: string
    config: Config
  }) {
    const host = params.config.wsHost

    this.clientUid = params.clientUid
    this.projectId = params.projectId

    this.client = new Echo({
      broadcaster: 'socket.io',
      key: 'random',
      cluster: 'mt1',
      host,
      transports: ['websocket', 'polling', 'flashsocket'],
      auth: {
        headers: {
          Authorization: 'Bearer ' + params.authToken,
          host: location.hostname,
        },
      },
    })

    return this
  }

  onNewNotification(fn: NewNotificationCb) {
    this.getPrivateChannel().listen(Events.New, fn)

    return this
  }

  onCloseNotification(fn: CloseNotificationCb) {
    this.getPrivateChannel().listen(Events.Close, fn)

    return this
  }

  onCloseAllNotifications(fn: CloseNotificationsCb) {
    this.getPrivateChannel().listen(Events.CloseAll, fn)

    return this
  }

  onDisconnect(fn: any) {
    this.client.connector.socket.on('disconnect', fn)

    return this
  }

  onConnect(fn: any) {
    this.client.connector.socket.on('connect', fn)

    return this
  }

  connect() {
    return this.client.connect()
  }

  disconnect() {
    return this.client.disconnect()
  }

  private getPrivateChannel(): SocketIoPrivateChannel {
    return this.client.private(
      `notification.${this.clientUid}.${this.projectId}`
    ) as SocketIoPrivateChannel
  }
}

export default new NotificationWebsocketService()
