import Echo from 'laravel-echo'
import io from 'socket.io-client'
import { SocketIoPrivateChannel } from 'laravel-echo/dist/channel'
import { NotificationEvent } from '@/widgets/notifications/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

  init(params: { authToken: string; clientUid: string }) {
    this.clientUid = params.clientUid

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

    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}.${process.env.PROJECT_NAME}`
    ) as SocketIoPrivateChannel
  }
}

export default new NotificationWebsocketService()
