/**
 * 语音识别工具
 * 使用 Web Speech API 进行浏览器端语音识别
 */

// Web Speech API 类型声明
interface SpeechRecognitionEvent extends Event {
  results: SpeechRecognitionResultList
  resultIndex: number
}

interface SpeechRecognitionResultList {
  readonly length: number
  item(index: number): SpeechRecognitionResult
  [index: number]: SpeechRecognitionResult
}

interface SpeechRecognitionResult {
  readonly length: number
  readonly isFinal: boolean
  item(index: number): SpeechRecognitionAlternative
  [index: number]: SpeechRecognitionAlternative
}

interface SpeechRecognitionAlternative {
  readonly transcript: string
  readonly confidence: number
}

interface SpeechRecognitionErrorEvent extends Event {
  error: string
  message: string
}

declare global {
  interface Window {
    SpeechRecognition: new () => SpeechRecognition
    webkitSpeechRecognition: new () => SpeechRecognition
  }
}

interface SpeechRecognition extends EventTarget {
  continuous: boolean
  interimResults: boolean
  lang: string
  maxAlternatives: number
  start(): void
  stop(): void
  abort(): void
  onresult: ((event: SpeechRecognitionEvent) => void) | null
  onerror: ((event: SpeechRecognitionErrorEvent) => void) | null
  onend: (() => void) | null
  onstart: (() => void) | null
  onspeechend: (() => void) | null
}

// 语音识别配置
export interface SpeechRecognitionConfig {
  continuous?: boolean
  interimResults?: boolean
  lang?: string
  maxAlternatives?: number
}

// 语音识别结果
export interface SpeechRecognitionResult {
  transcript: string
  isFinal: boolean
  confidence: number
}

// 语音识别回调
export interface SpeechRecognitionCallbacks {
  onResult?: (result: SpeechRecognitionResult) => void
  onError?: (error: string) => void
  onStart?: () => void
  onEnd?: () => void
}

/**
 * 检查浏览器是否支持语音识别
 */
export function isSpeechRecognitionSupported(): boolean {
  return !!(window.SpeechRecognition || window.webkitSpeechRecognition)
}

/**
 * 创建语音识别实例
 */
export function createSpeechRecognition(
  config: SpeechRecognitionConfig = {}
): SpeechRecognition | null {
  const SpeechRecognitionConstructor =
    window.SpeechRecognition || window.webkitSpeechRecognition

  if (!SpeechRecognitionConstructor) {
    console.warn('浏览器不支持语音识别')
    return null
  }

  const recognition = new SpeechRecognitionConstructor()
  recognition.continuous = config.continuous ?? false
  recognition.interimResults = config.interimResults ?? true
  recognition.lang = config.lang ?? 'zh-CN'
  recognition.maxAlternatives = config.maxAlternatives ?? 1

  return recognition
}

/**
 * 语音识别管理器类
 */
export class SpeechRecognitionManager {
  private recognition: SpeechRecognition | null = null
  private isListening = false
  private callbacks: SpeechRecognitionCallbacks = {}

  constructor(config: SpeechRecognitionConfig = {}) {
    this.recognition = createSpeechRecognition(config)
    this.setupEventListeners()
  }

  private setupEventListeners() {
    if (!this.recognition) return

    this.recognition.onresult = (event: SpeechRecognitionEvent) => {
      const lastResult = event.results[event.resultIndex]
      if (lastResult) {
        const result: SpeechRecognitionResult = {
          transcript: lastResult[0].transcript,
          isFinal: lastResult.isFinal,
          confidence: lastResult[0].confidence,
        }
        this.callbacks.onResult?.(result)
      }
    }

    this.recognition.onerror = (event: SpeechRecognitionErrorEvent) => {
      const errorMessages: Record<string, string> = {
        'no-speech': '没有检测到语音',
        'audio-capture': '无法访问麦克风',
        'not-allowed': '麦克风权限被拒绝',
        'network': '网络错误',
        'aborted': '识别被中断',
        'language-not-supported': '不支持的语言',
      }
      const message = errorMessages[event.error] || `识别错误: ${event.error}`
      this.callbacks.onError?.(message)
      this.isListening = false
    }

    this.recognition.onstart = () => {
      this.isListening = true
      this.callbacks.onStart?.()
    }

    this.recognition.onend = () => {
      this.isListening = false
      this.callbacks.onEnd?.()
    }
  }

  /**
   * 设置回调函数
   */
  setCallbacks(callbacks: SpeechRecognitionCallbacks) {
    this.callbacks = callbacks
  }

  /**
   * 开始语音识别
   */
  start(): boolean {
    if (!this.recognition) {
      this.callbacks.onError?.('浏览器不支持语音识别')
      return false
    }

    if (this.isListening) {
      return true
    }

    try {
      this.recognition.start()
      return true
    } catch (error) {
      this.callbacks.onError?.('启动语音识别失败')
      return false
    }
  }

  /**
   * 停止语音识别
   */
  stop() {
    if (this.recognition && this.isListening) {
      this.recognition.stop()
    }
  }

  /**
   * 中止语音识别
   */
  abort() {
    if (this.recognition) {
      this.recognition.abort()
    }
  }

  /**
   * 是否正在监听
   */
  getIsListening(): boolean {
    return this.isListening
  }

  /**
   * 是否支持语音识别
   */
  isSupported(): boolean {
    return this.recognition !== null
  }

  /**
   * 销毁实例
   */
  destroy() {
    this.abort()
    this.recognition = null
  }
}

/**
 * 一次性语音识别
 * 返回 Promise，识别完成后返回结果
 */
export function recognizeSpeech(
  config: SpeechRecognitionConfig = {},
  timeout = 10000
): Promise<string> {
  return new Promise((resolve, reject) => {
    const manager = new SpeechRecognitionManager({
      ...config,
      continuous: false,
      interimResults: false,
    })

    if (!manager.isSupported()) {
      reject(new Error('浏览器不支持语音识别'))
      return
    }

    let finalTranscript = ''
    let timeoutId: number | null = null

    manager.setCallbacks({
      onResult: (result) => {
        if (result.isFinal) {
          finalTranscript = result.transcript
        }
      },
      onEnd: () => {
        if (timeoutId) {
          clearTimeout(timeoutId)
        }
        manager.destroy()
        resolve(finalTranscript)
      },
      onError: (error) => {
        if (timeoutId) {
          clearTimeout(timeoutId)
        }
        manager.destroy()
        reject(new Error(error))
      },
    })

    // 设置超时
    timeoutId = window.setTimeout(() => {
      manager.stop()
    }, timeout)

    if (!manager.start()) {
      reject(new Error('启动语音识别失败'))
    }
  })
}

export default {
  isSpeechRecognitionSupported,
  createSpeechRecognition,
  SpeechRecognitionManager,
  recognizeSpeech,
}
