import config from '@/application/config'
import { SocketEvent } from '@/application/enums'
import { useCookies } from '@vueuse/integrations/useCookies'
import { io, Socket } from 'socket.io-client'
import { ref, shallowRef } from 'vue'

class SocketManager {
  private static instance: SocketManager
  private _connection = shallowRef<Socket | null>(null)
  private _token = ref('')

  private constructor() {}

  public static getInstance(): SocketManager {
    if (!SocketManager.instance) {
      SocketManager.instance = new SocketManager()
    }
    return SocketManager.instance
  }

  public get connection() {
    return this._connection.value
  }

  public get token() {
    return this._token.value
  }

  public setToken(token: string) {
    this._token.value = token
  }

  public initConnection(): Socket {
    if (this._connection.value) return this._connection.value

    const socket = io(config.server_endpoint, {
      secure: config.environment === 'production',
      withCredentials: true,
      transports: ['websocket'],
      reconnectionAttempts: 5
    })

    this._connection.value = socket
    return socket
  }

  public disconnect(): void {
    if (!this._connection.value) return

    this._connection.value.off(SocketEvent.CONNECT_ERROR)
    this._connection.value.off(SocketEvent.RECONNECT_FAILED)
    this._connection.value.off(SocketEvent.DATE)
    this._connection.value.disconnect()

    useCookies().remove('token', {
      domain: config.domain
    })

    this._connection.value = null
    this._token.value = ''
  }

  public emit(event: string, ...args: any[]): void {
    this._connection.value?.emit(event, ...args)
  }

  public on(event: string, callback: (...args: any[]) => void): void {
    this._connection.value?.on(event, callback)
  }

  public off(event: string, callback?: (...args: any[]) => void): void {
    this._connection.value?.off(event, callback)
  }
}

export const socketManager = SocketManager.getInstance()