import { ClientMsg } from '../network/pbExport'
import { EventType } from '../constant'
import { PbHelper } from '../network/pbHelper'

export class WsClient {
  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 Instance(): WsClient {
    if (!this.instance) this.instance = new WsClient()
    return this.instance
  }

  // 是否连接
  public get IsConnected(): boolean {
    return this.isConnected
  }

  // 关闭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
  }

  private async connectAsync(url?: string): Promise<WebSocket> {
    if (this.socket && this.socket.readyState !== WebSocket.CLOSED) {
      // 如果已有连接且未关闭
      this.Close()
    }
    return new Promise((resolve, reject) => {
      const ws = new WebSocket(url)
      ws.onopen = () => resolve(ws)
      ws.onerror = (err) => reject(err)
      ws.onclose = () => reject(new Error('连接已关闭'))
    })
  }

  // // 使用示例
  // async function sendMessage() {
  //   try {
  //     const ws = await connectWebSocket();
  //     console.log('连接已建立');
  //     ws.send('同步发送消息');
  //   } catch (err) {
  //     console.error('连接失败:', err);
  //   }
  // }

  // 连接websocket服务器
  async ConnectAsync(url?: string) {
    if (url) this.url = url
    url = this.url
    try {
      console.log(`正在连接websocket服务器:${url}`)
      this.socket = await this.connectAsync(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
    } catch (error) {
      console.error('创建websocket失败:', error)
      await this.ScheduleReconnect()
    }
  }

  // 发送消息到服务器
  Send(sid: number, msgId: number, msg: Uint8Array) {
    if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
      // 如果连接不存在或未打开
      console.error('websocket未连接,无法发送消息')
      return false
    }
    const clinetMsg = new ClientMsg()
    clinetMsg.msgId = msgId
    clinetMsg.data = msg
    clinetMsg.serviceTid = sid
    const buffer = ClientMsg.encode(clinetMsg).finish()
    this.socket.send(buffer)
    return true
  }

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

  // 收到消息回调
  private async onMessage(event: MessageEvent) {
    try {
      const buffer = await event.data.arrayBuffer()
      const uint8Array = new Uint8Array(buffer)
      // console.log('收到消息:', uint8Array)
      console.log('收到消息:', PbHelper.Uint8ToHex(uint8Array))
      window.dispatchEvent(new CustomEvent(EventType.Ws, { detail: uint8Array }))
    } catch (error) {
      console.error('解析网络消息失败:', error)
    }
  }

  // 连接关闭回调
  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 async ScheduleReconnect() {
    if (this.reconnectCount >= this.maxReconnectCount) {
      console.error(`达到最大重连次数:${this.maxReconnectCount},停止重连`)
      return
    }

    this.reconnectCount++
    console.log(`尝试重连(${this.reconnectCount}/${this.maxReconnectCount})...`)
    await this.connectAsync()
  }
}
