import { _decorator, Component, Node } from 'cc'
const { ccclass, property } = _decorator

@ccclass('WsClient')
export class WsClient extends Component {
  private socket: WebSocket | null = null
  private url: string = 'ws://echo.websocket.org' // 测试服务器
  private reconnectTimerId: number = 0
  private maxReconnectCount: number = 5
  private reconnectCount: number = 0
  private isConnected: boolean = false

  private static instance: WsClient = null

  // 单例
  public static get Instance(): WsClient {
    return this.instance
  }

  public get IsConnected(): boolean {
    return this.isConnected
  }

  // 组件加载时自动调用
  protected onLoad(): void {
    if (WsClient.instance) {
      this.destroy()
      return
    }
    WsClient.instance = this
    this.node.name = 'WsClient'
    this.node.addComponent(WsClient)
  }

  // 关闭WebSocket连接
  close() {
    if (this.reconnectTimerId > 0) {
      clearTimeout(this.reconnectTimerId)
      this.reconnectTimerId = 0
    }
    if (this.socket) {
      // 清空所有事件处理函数
      this.socket.onopen = null
      this.socket.onmessage = null
      this.socket.onclose = null
      this.socket.onerror = null
      this.socket.close()
      this.socket = null
    }
    this.isConnected = false
  }

  // 连接websocket服务器
  connect(url?: string) {
    if (url) this.url = url
    if (this.socket && this.socket.readyState !== WebSocket.CLOSED) {
      // 如果已有连接且未关闭
      this.close()
    }
    try {
      this.socket = new WebSocket(this.url)
      this.socket.onopen = this.onOpen.bind(this)
      this.socket.onmessage = this.onMessage.bind(this)
      this.socket.onclose = this.onClose.bind(this)
      this.socket.onerror = this.onError.bind(this)
      this.reconnectCount = 0
      this.isConnected = true
      console.log(`正在连接websocket服务器:${this.url}`)
    } catch (error) {
      console.error('创建websocket失败:', error)
      this.scheduleReconnect()
    }
  }

  // 发送消息到服务器
  send(message: string | object) {
    if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
      // 如果连接不存在或未打开
      console.error('websocket未连接,无法发送消息')
      return false
    }
    var msg: string = ''
    if (typeof message == 'string') {
      msg = message
    } else {
      msg = JSON.stringify(message)
    }
    this.socket.send(msg)
    return true
  }

  // 连接成功回调
  private onOpen() {
    console.log('websocket连接已建立')
    this.reconnectCount = 0
  }

  // 收到消息回调
  private onMessage(event: MessageEvent) {
    console.log('收到消息:', event.data)
    window.dispatchEvent(new CustomEvent('ws-message', { detail: event.data }))
  }

  // 连接关闭回调
  private onClose(event: CloseEvent) {
    console.log('websocket连接已关闭,代码:', event.code, '原因:', event.reason)
    this.socket = null
    this.scheduleReconnect()
  }

  // 连接错误回调
  private onError(error: Event) {
    console.error('websocket发生错误:', error)
    // 不需要在这里重连，onClose里会重连
  }

  // 重连
  private scheduleReconnect() {
    if (this.reconnectCount >= this.maxReconnectCount) {
      console.error(`达到最大重连次数:${this.maxReconnectCount},停止重连`)
      return
    }

    this.reconnectCount++
    const delay = 2000
    console.log(
      `尝试重连(${this.reconnectCount}/${this.maxReconnectCount}),${
        delay / 1000
      }秒后...`
    )
    this.reconnectTimerId = setTimeout(() => {
      this.connect()
    }, delay)
  }

  // 组件销毁时自动调用
  protected onDestroy(): void {
    this.close()
  }
}
