import { tokenManager } from '@/lib/auth/token'

export type ConnectionState = 'connecting' | 'connected' | 'disconnected' | 'error'

export interface TTSConfig {
  voiceType?: string
  speechRate?: number
  pitchRate?: number
  aiId?: number
}

export interface TTSWebSocketManager {
  subscribe(
    messageId: string,
    onChunk: (data: string, sort: number, messageId: string) => void,
    onEnd?: (messageId: string) => void
  ): void
  unsubscribe(messageId: string): void
  sendText(messageId: string, text: string, config?: TTSConfig): Promise<void>
  getConnectionState(): ConnectionState
  connect(): Promise<void>
  disconnect(): void
}

interface Subscriber {
  onChunk: (data: string, sort: number, messageId: string) => void
  onEnd?: (messageId: string) => void
}

class TTSWebSocketManagerImpl implements TTSWebSocketManager {
  private ws: WebSocket | null = null
  private connectionState: ConnectionState = 'disconnected'
  private subscribers: Map<string, Subscriber> = new Map()
  private reconnectAttempts = 0
  private maxReconnectAttempts = 5
  private reconnectDelay = 1000
  private isConnecting = false
  private connectionPromise: Promise<void> | null = null

  private readonly WS_URL = 'wss://gxfs6w4f57.execute-api.us-west-2.amazonaws.com/production'

  constructor() {
    // 监听页面可见性变化，页面隐藏时断开连接，显示时重连
    if (typeof window !== 'undefined') {
      document.addEventListener('visibilitychange', this.handleVisibilityChange.bind(this))
    }
  }

  private handleVisibilityChange() {
    if (document.hidden) {
      // 页面隐藏时断开连接
      this.disconnect()
    } else if (this.subscribers.size > 0) {
      // 页面显示且有订阅者时重连
      this.connect()
    }
  }

  async connect(): Promise<void> {
    if (this.isConnecting && this.connectionPromise) {
      return this.connectionPromise
    }

    if (this.ws?.readyState === WebSocket.OPEN) {
      return Promise.resolve()
    }

    this.isConnecting = true
    this.connectionState = 'connecting'

    this.connectionPromise = new Promise((resolve, reject) => {
      try {
        const token = tokenManager.getToken()
        if (!token) {
          throw new Error('No authentication token available')
        }

        const wsUrl = `${this.WS_URL}?token=${encodeURIComponent(token)}`
        this.ws = new WebSocket(wsUrl)

        this.ws.onopen = () => {
          console.log('TTS WebSocket connected')
          this.connectionState = 'connected'
          this.reconnectAttempts = 0
          this.isConnecting = false
          resolve()
        }

        this.ws.onmessage = (event) => {
          try {
            const data = JSON.parse(JSON.parse(event.data))

            // 处理音频数据: { data: base64, sort: 0, messageId: 'xxx' }
            if (
              data.data &&
              typeof data.data === 'string' &&
              typeof data.sort === 'number' &&
              data.messageId
            ) {
              const subscriber = this.subscribers.get(data.messageId)
              if (subscriber) {
                subscriber.onChunk(data.data, data.sort, data.messageId)
              }
            }

            // 处理结束信号: { status: "END", messageId: "xxx" }
            if (data.status === 'END' && data.messageId) {
              const subscriber = this.subscribers.get(data.messageId)
              if (subscriber && subscriber.onEnd) {
                subscriber.onEnd(data.messageId)
              }
            }
          } catch (error) {
            console.error('Failed to parse WebSocket message:', error)
          }
        }

        this.ws.onclose = (event) => {
          console.log('TTS WebSocket closed:', event.code, event.reason)
          this.connectionState = 'disconnected'
          this.isConnecting = false

          // 如果不是主动关闭且有订阅者，尝试重连
          if (event.code !== 1000 && this.subscribers.size > 0) {
            this.scheduleReconnect()
          }
        }

        this.ws.onerror = (error) => {
          console.error('TTS WebSocket error:', error)
          this.connectionState = 'error'
          this.isConnecting = false
          reject(new Error('WebSocket connection failed'))
        }
      } catch (error) {
        this.isConnecting = false
        this.connectionState = 'error'
        reject(error)
      }
    })

    return this.connectionPromise
  }

  private scheduleReconnect() {
    if (this.reconnectAttempts >= this.maxReconnectAttempts) {
      console.error('Max reconnection attempts reached')
      this.connectionState = 'error'
      return
    }

    this.reconnectAttempts++
    const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1) // 指数退避

    setTimeout(() => {
      if (this.subscribers.size > 0) {
        console.log(
          `Attempting to reconnect (${this.reconnectAttempts}/${this.maxReconnectAttempts})`
        )
        this.connect().catch(console.error)
      }
    }, delay)
  }

  disconnect(): void {
    if (this.ws) {
      this.ws.close(1000, 'Manual disconnect')
      this.ws = null
    }
    this.connectionState = 'disconnected'
    this.isConnecting = false
    this.connectionPromise = null
  }

  subscribe(
    messageId: string,
    onChunk: (data: string, sort: number, messageId: string) => void,
    onEnd?: (messageId: string) => void
  ): void {
    this.subscribers.set(messageId, { onChunk, onEnd })

    // 如果有订阅者但没有连接，则连接
    if (this.connectionState === 'disconnected' || this.connectionState === 'error') {
      this.connect().catch(console.error)
    }
  }

  unsubscribe(messageId: string): void {
    this.subscribers.delete(messageId)

    // 如果没有订阅者了，断开连接
    if (this.subscribers.size === 0) {
      this.disconnect()
    }
  }

  async sendText(messageId: string, text: string, config?: TTSConfig): Promise<void> {
    if (this.connectionState !== 'connected' || !this.ws) {
      await this.connect()
    }

    if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
      throw new Error('WebSocket is not connected')
    }

    const message = {
      messageId,
      text: text,
      ...(config && {
        voiceType: config.voiceType,
        speechRate: config.speechRate,
        pitchRate: config.pitchRate,
        aiId: config.aiId,
      }),
    }

    this.ws.send(JSON.stringify(message))
  }

  getConnectionState(): ConnectionState {
    return this.connectionState
  }
}

// 全局单例
export const ttsWebSocketManager = new TTSWebSocketManagerImpl()
