import { useState, useRef, useCallback, useEffect } from 'react'
import { FetchVoiceTtsV2Request } from '@/services/common/types'
import { ChatPriceType, COIN_INSUFFICIENT_ERROR_CODE, useUpdateWalletBalance } from './useWallet'
import { useSetAtom } from 'jotai'
import { isCoinInsufficientAtom } from '@/atoms/im'
import { ApiError } from '@/types/api'
import { ttsWebSocketManager, TTSConfig } from '@/lib/websocket/tts-websocket'
import { createAudioChunkPlayer, AudioChunkPlayer } from '@/lib/audio/audio-chunk-player'

interface VoiceTTSCache {
  [key: string]: string // 缓存配置的hash作为key，blob url作为value
}

interface UseVoiceTTSOptions {
  cacheEnabled?: boolean // 是否启用缓存，默认为true
  needCheckSufficient?: boolean // 是否需要检查余额，默认为false
  onGenerateStart?: (config: FetchVoiceTtsV2Request) => void
  onGenerateEnd?: (config: FetchVoiceTtsV2Request, blobUrl: string) => void
  onError?: (error: string) => void
  aiId?: number
}

interface UseVoiceTTSReturn {
  isGenerating: boolean
  error: string | null
  generateAudioUrl: (config: FetchVoiceTtsV2Request) => Promise<string>
  clearCache: () => void
  getCachedBlobUrl: (config: FetchVoiceTtsV2Request) => string | null
  isPlaying: boolean
  stopPlayback: () => void
}

/**
 * 语音合成流式播放的自定义Hook
 *
 * 功能特性：
 * 1. WebSocket 流式传输：通过 WebSocket 实时接收音频片段
 * 2. 智能缓存：相同配置的语音只生成一次，存储 Blob URL 在内存中
 * 3. 流式播放：使用 Web Audio API 顺序播放音频片段，提升响应速度
 * 4. 错误处理：完善的错误处理和状态管理
 * 5. 配置哈希：通过配置内容生成唯一标识，用于缓存
 * 6. 内存管理：自动清理 Blob URLs 防止内存泄漏
 */
export function useVoiceTTS(options: UseVoiceTTSOptions = {}): UseVoiceTTSReturn {
  const {
    cacheEnabled = true,
    needCheckSufficient,
    onGenerateStart,
    onGenerateEnd,
    onError,
  } = options

  const [isGenerating, setIsGenerating] = useState(false)
  const [isPlaying, setIsPlaying] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const cacheRef = useRef<VoiceTTSCache>({})
  const audioPlayerRef = useRef<AudioChunkPlayer | null>(null)
  const messageIdRef = useRef<string | null>(null)
  const currentConfigRef = useRef<FetchVoiceTtsV2Request | null>(null)

  const { checkSufficientByType } = useUpdateWalletBalance()
  const setIsCoinInsufficient = useSetAtom(isCoinInsufficientAtom)

  // 生成唯一消息ID
  const generateMessageId = useCallback((): string => {
    return `tts_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
  }, [])

  // 生成配置的哈希值，用于缓存标识
  const generateConfigHash = useCallback((config: FetchVoiceTtsV2Request): string => {
    const configString = JSON.stringify({
      text: config.text,
      voiceType: config.voiceType,
      speechRate: config.speechRate,
      pitchRate: config.pitchRate,
      aiId: config.aiId,
    })
    // 简单的哈希函数
    let hash = 0
    for (let i = 0; i < configString.length; i++) {
      const char = configString.charCodeAt(i)
      hash = (hash << 5) - hash + char
      hash = hash & hash // 转换为32位整数
    }
    return Math.abs(hash).toString(36)
  }, [])

  // 初始化音频播放器
  const initializeAudioPlayer = useCallback(() => {
    if (!audioPlayerRef.current) {
      audioPlayerRef.current = createAudioChunkPlayer()

      // 监听播放开始
      audioPlayerRef.current.onPlaybackStart(() => {
        setIsPlaying(true)
      })

      // 监听播放结束
      audioPlayerRef.current.onPlaybackEnd(() => {
        setIsPlaying(false)
        // 播放完成后，合并音频片段并缓存
        if (currentConfigRef.current) {
          mergeAndCacheAudio(currentConfigRef.current)
        }
      })
    }
    return audioPlayerRef.current
  }, [])

  // 合并音频片段并缓存
  const mergeAndCacheAudio = useCallback(
    async (config: FetchVoiceTtsV2Request) => {
      try {
        if (!audioPlayerRef.current) {
          console.error('Audio player not available for merging')
          return
        }

        // 获取所有音频片段
        const audioChunks = audioPlayerRef.current.getAllAudioChunks()
        if (audioChunks.length === 0) {
          console.warn('No audio chunks to merge')
          return
        }

        // 将base64音频片段转换为buffer并合并
        const audioBuffers: ArrayBuffer[] = []
        for (const chunk of audioChunks) {
          try {
            // 将base64转换为ArrayBuffer
            const binaryString = atob(chunk.data)
            const bytes = new Uint8Array(binaryString.length)
            for (let i = 0; i < binaryString.length; i++) {
              bytes[i] = binaryString.charCodeAt(i)
            }
            audioBuffers.push(bytes.buffer)
          } catch (error) {
            console.error(`Failed to convert chunk ${chunk.sort} from base64:`, error)
          }
        }

        // 计算总长度
        const totalLength = audioBuffers.reduce((sum, buffer) => sum + buffer.byteLength, 0)

        // 创建合并后的ArrayBuffer
        const mergedBuffer = new ArrayBuffer(totalLength)
        const mergedView = new Uint8Array(mergedBuffer)

        // 将各个buffer复制到合并后的buffer中
        let offset = 0
        for (const buffer of audioBuffers) {
          mergedView.set(new Uint8Array(buffer), offset)
          offset += buffer.byteLength
        }

        // 创建blob
        const audioBlob = new Blob([mergedBuffer], { type: 'audio/mpeg' })
        const blobUrl = URL.createObjectURL(audioBlob)

        const hash = generateConfigHash(config)

        if (cacheEnabled) {
          cacheRef.current[hash] = blobUrl
        }

        onGenerateEnd?.(config, blobUrl)
      } catch (error) {
        console.error('Failed to merge and cache audio:', error)
      }
    },
    [generateConfigHash, cacheEnabled, onGenerateEnd]
  )

  // 从缓存中获取Blob URL
  const getCachedBlobUrl = useCallback(
    (config: FetchVoiceTtsV2Request): string | null => {
      if (!cacheEnabled) return null
      const hash = generateConfigHash(config)
      return cacheRef.current[hash] || null
    },
    [generateConfigHash, cacheEnabled]
  )

  // 停止播放
  const stopPlayback = useCallback(() => {
    if (audioPlayerRef.current) {
      audioPlayerRef.current.stop()
      setIsPlaying(false)
    }
  }, [])

  // 生成语音URL（流式播放）
  const generateAudioUrl = useCallback(
    async (config: FetchVoiceTtsV2Request): Promise<string> => {
      try {
        setError(null)

        // 检查缓存
        const cachedBlobUrl = getCachedBlobUrl(config)
        if (cachedBlobUrl) {
          return cachedBlobUrl
        }

        if (needCheckSufficient && !checkSufficientByType(ChatPriceType.VOICE)) {
          setIsCoinInsufficient(true)
          return ''
        }

        setIsGenerating(true)
        onGenerateStart?.(config)

        // 保存当前配置
        currentConfigRef.current = config

        // 生成消息ID
        const messageId = generateMessageId()
        messageIdRef.current = messageId

        // 初始化音频播放器
        const audioPlayer = initializeAudioPlayer()

        // 订阅 WebSocket 消息
        console.log('subscribe ttsWebSocketManager', messageId)
        ttsWebSocketManager.subscribe(messageId, (data, sort) => {
          console.log('subscribe ttsWebSocketManager', sort, data)
          audioPlayer.addChunk(sort, data)
        })

        // 发送文本到 WebSocket
        const ttsConfig: TTSConfig = {
          voiceType: config.voiceType,
          speechRate: config.speechRate,
          pitchRate: config.pitchRate,
          aiId: config.aiId,
        }

        await ttsWebSocketManager.sendText(messageId, config.text || '', ttsConfig)

        // 开始播放
        await audioPlayer.play()

        // 返回一个占位的 URL，实际播放是通过 WebSocket 流式进行的
        const hash = generateConfigHash(config)
        const placeholderBlob = new Blob([''], { type: 'audio/mpeg' })
        const blobUrl = URL.createObjectURL(placeholderBlob)

        return blobUrl
      } catch (err) {
        if (needCheckSufficient) {
          if (err instanceof ApiError && err.errorCode === COIN_INSUFFICIENT_ERROR_CODE) {
            setIsCoinInsufficient(true)
            return ''
          }
        }
        const errorMessage = err instanceof Error ? err.message : '语音合成失败'
        setError(errorMessage)
        onError?.(errorMessage)
        console.error('语音合成失败:', err)
        return ''
      } finally {
        setIsGenerating(false)
      }
    },
    [
      getCachedBlobUrl,
      generateConfigHash,
      cacheEnabled,
      onGenerateStart,
      onGenerateEnd,
      onError,
      needCheckSufficient,
      checkSufficientByType,
      setIsCoinInsufficient,
      generateMessageId,
      initializeAudioPlayer,
    ]
  )

  // 清除缓存
  const clearCache = useCallback(() => {
    // 释放所有Blob URL以避免内存泄漏
    Object.values(cacheRef.current).forEach((blobUrl) => {
      URL.revokeObjectURL(blobUrl)
    })
    cacheRef.current = {}
  }, [])

  // 组件挂载时初始化 WebSocket 连接
  useEffect(() => {
    // 组件挂载时，WebSocket 连接会在第一次调用 generateAudioUrl 时建立
    return () => {
      // 组件卸载时清理
      if (messageIdRef.current) {
        ttsWebSocketManager.unsubscribe(messageIdRef.current)
      }
      if (audioPlayerRef.current) {
        audioPlayerRef.current.destroy()
        audioPlayerRef.current = null
      }
      // 释放所有Blob URL以避免内存泄漏
      Object.values(cacheRef.current).forEach((blobUrl) => {
        URL.revokeObjectURL(blobUrl)
      })
    }
  }, [])

  return {
    isGenerating,
    error,
    generateAudioUrl,
    clearCache,
    getCachedBlobUrl,
    isPlaying,
    stopPlayback,
  }
}
