/**
 * VoiceOutput - 独立语音合成 SDK
 * 基于讯飞语音合成 WebAPI（流式版）
 *
 * 零依赖，纯原生 JS，任何静态 HTML 页面都能用
 *
 * 用法：
 *   const tts = new VoiceOutput({
 *     onAudio: (audioData) => { ... }
 *   });
 *   tts.speak("你好世界");  // 开始合成
 *   tts.stop();            // 停止
 */
(function (global) {
  'use strict';

  // ============ 默认配置 ============
  var DEFAULT_CONFIG = {
    APPID: '',
    APISecret: '',
    APIKey: '',
    url: 'wss://tts-api.xfyun.cn/v2/tts',
    host: 'tts-api.xfyun.cn',
    vcn: 'x4_xiaoyan',    // 默认语音
    speed: 50,            // 语速 0-100
    pitch: 50,             // 音调 0-100
    volume: 50,            // 音量 0-100
    aue: 'lame',          // 音频格式: lame=mp3, raw=pcm
  };

  // ============ 工具函数 ============

  function hmacSHA256(key, message) {
    var enc = new TextEncoder();
    return crypto.subtle.importKey(
      'raw', enc.encode(key), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']
    ).then(function (cryptoKey) {
      return crypto.subtle.sign('HMAC', cryptoKey, enc.encode(message));
    }).then(function (sig) {
      return arrayBufferToBase64(sig);
    });
  }

  function arrayBufferToBase64(buffer) {
    var binary = '';
    var bytes = new Uint8Array(buffer);
    for (var i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
    return btoa(binary);
  }

  function base64ToArrayBuffer(base64) {
    var binaryStr = atob(base64);
    var bytes = new Uint8Array(binaryStr.length);
    for (var i = 0; i < binaryStr.length; i++) bytes[i] = binaryStr.charCodeAt(i);
    return bytes.buffer;
  }

  // ============ VoiceOutput 类 ============

  function VoiceOutput(opts) {
    opts = opts || {};

    this.APPID = opts.APPID || DEFAULT_CONFIG.APPID;
    this.APISecret = opts.APISecret || DEFAULT_CONFIG.APISecret;
    this.APIKey = opts.APIKey || DEFAULT_CONFIG.APIKey;
    this.url = opts.url || DEFAULT_CONFIG.url;
    this.host = opts.host || DEFAULT_CONFIG.host;
    this.vcn = opts.vcn || DEFAULT_CONFIG.vcn;
    this.speed = opts.speed || DEFAULT_CONFIG.speed;
    this.pitch = opts.pitch || DEFAULT_CONFIG.pitch;
    this.volume = opts.volume || DEFAULT_CONFIG.volume;
    this.aue = opts.aue || DEFAULT_CONFIG.aue;

    // 回调
    this.onAudio = opts.onAudio || function (audioBuffer) {};  // 音频数据回调
    this.onStatusChange = opts.onStatusChange || function () {};
    this.onError = opts.onError || function () {};

    // 内部状态
    this.status = 'idle'; // idle | connecting | synthesizing | stopping | stopped
    this.webSocket = null;
    this.audioContext = null;
    this.audioChunks = [];
    this.audioSource = null;
    this.onAudioEnd = null;
  }

  VoiceOutput.prototype._getWebSocketUrl = function () {
    var self = this;
    var date = new Date().toUTCString();
    var signatureOrigin = 'host: ' + self.host + '\ndate: ' + date + '\nGET /v2/tts HTTP/1.1';

    return hmacSHA256(self.APISecret, signatureOrigin).then(function (signature) {
      var authOrigin = 'api_key="' + self.APIKey + '", algorithm="hmac-sha256", headers="host date request-line", signature="' + signature + '"';
      var authorization = btoa(authOrigin);
      return self.url + '?authorization=' + authorization + '&date=' + encodeURIComponent(date) + '&host=' + self.host;
    });
  };

  VoiceOutput.prototype._initAudioContext = function () {
    if (!this.audioContext) {
      this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
    }
    return this.audioContext;
  };

  VoiceOutput.prototype._playAudio = function (audioBuffer) {
    var self = this;

    // 尝试 Web Audio API（可以解码 MP3）
    try {
      this._initAudioContext();
      this.audioContext.decodeAudioData(audioBuffer.slice(0), function (decodedBuffer) {
        console.log('[tts] decoded audio:', decodedBuffer.duration, 's,', decodedBuffer.numberOfChannels, 'ch');
        self._playBuffer(decodedBuffer);
      }, function (err) {
        console.error('[tts] decode error, trying blob URL:', err);
        // fallback: 用 Blob URL 方式
        self._playAudioBlob(audioBuffer);
      });
      return;
    } catch (e) {
      console.error('[tts] Web Audio API error:', e);
      // fallback: 用 Blob URL 方式
    }

    this._playAudioBlob(audioBuffer);
  };

  VoiceOutput.prototype._playAudioBlob = function (audioBuffer) {
    var self = this;

    // 创建 Blob URL 用于 <audio> 元素播放
    var mimeType = this.aue === 'lame' ? 'audio/mpeg' : 'audio/wav';
    var blob = new Blob([audioBuffer], { type: mimeType });
    console.log('[tts] blob size:', blob.size, 'type:', mimeType);
    var blobUrl = URL.createObjectURL(blob);

    // 停止之前的播放
    if (this.currentAudio) {
      this.currentAudio.pause();
      URL.revokeObjectURL(this.currentAudioSrc);
    }

    // 创建 audio 元素播放
    var audio = new Audio(blobUrl);
    this.currentAudio = audio;
    this.currentAudioSrc = blobUrl;

    audio.play().then(function () {
      console.log('[tts] playing...');
    }).catch(function (err) {
      console.error('[tts] play error:', err);
      self.onError('播放失败: ' + err.message);
    });

    audio.onended = function () {
      URL.revokeObjectURL(blobUrl);
      if (self.onAudioEnd) {
        self.onAudioEnd();
      }
    };
  };

  VoiceOutput.prototype._playBuffer = function (audioBuffer) {
    var source = this.audioContext.createBufferSource();
    source.buffer = audioBuffer;
    source.connect(this.audioContext.destination);
    source.start(0);
    this.audioSource = source;

    source.onended = function () {
      if (self.onAudioEnd) {
        self.onAudioEnd();
      }
    };
  };

  VoiceOutput.prototype.speak = function (text, opts) {
    if (this.status === 'synthesizing') {
      console.warn('[tts] already synthesizing');
      return;
    }

    opts = opts || {};
    this.audioChunks = [];
    this._setStatus('connecting');

    var self = this;
    this._getWebSocketUrl().then(function (url) {
      var ws = new WebSocket(url);
      self.webSocket = ws;

      var timeout = setTimeout(function () {
        if (ws.readyState === WebSocket.CONNECTING) {
          ws.close();
          self.onError('WebSocket 连接超时');
          self._setStatus('idle');
        }
      }, 5000);

      ws.onopen = function () {
        clearTimeout(timeout);
        self._setStatus('synthesizing');

        // 构造 TTS 请求
        var textBase64 = btoa(unescape(encodeURIComponent(text)));

        var payload = {
          common: { app_id: self.APPID },
          business: {
            aue: self.aue,
            auf: 'audio/L16;rate=16000',
            vcn: opts.vcn || self.vcn,
            speed: opts.speed || self.speed,
            pitch: opts.pitch || self.pitch,
            volume: opts.volume || self.volume,
            tte: 'UTF8',
          },
          data: {
            status: 2,
            text: textBase64,
          },
        };

        ws.send(JSON.stringify(payload));
        console.log('[tts] sent text:', text.substring(0, 50) + (text.length > 50 ? '...' : ''));
      };

      ws.onmessage = function (event) {
        try {
          var msg = JSON.parse(event.data);

          if (msg.code !== 0) {
            self.onError('TTS error ' + msg.code + ': ' + msg.message);
            self._cleanup();
            return;
          }

          // 音频数据
          if (msg.data && msg.data.audio) {
            var audioData = base64ToArrayBuffer(msg.data.audio);
            self.audioChunks.push(audioData);
            self.onAudio(audioData);

            // 全部接收完成后播放
            if (msg.data.status === 2) {
              console.log('[tts] synthesis complete, chunks:', self.audioChunks.length);
              // 合并所有 chunks
              var totalLen = 0;
              for (var i = 0; i < self.audioChunks.length; i++) {
                totalLen += self.audioChunks[i].byteLength;
              }
              var merged = new Uint8Array(totalLen);
              var offset = 0;
              for (var j = 0; j < self.audioChunks.length; j++) {
                merged.set(new Uint8Array(self.audioChunks[j]), offset);
                offset += self.audioChunks[j].byteLength;
              }
              self._playAudio(merged.buffer);
              self._setStatus('idle');
            }
          }
        } catch (err) {
          console.error('[tts] parse error:', err);
        }
      };

      ws.onerror = function (err) {
        console.error('[tts] WebSocket error:', err);
        self.onError('WebSocket 连接错误');
        self._cleanup();
      };

      ws.onclose = function () {
        clearTimeout(timeout);
        if (self.status !== 'idle') {
          self._setStatus('idle');
        }
      };
    }).catch(function (err) {
      self.onError('签名失败: ' + err);
      self._setStatus('idle');
    });
  };

  VoiceOutput.prototype.stop = function () {
    this._setStatus('stopping');
    this._cleanup();
    this._setStatus('idle');
  };

  VoiceOutput.prototype._cleanup = function () {
    if (this.webSocket) {
      this.webSocket.close();
      this.webSocket = null;
    }
    if (this.audioSource) {
      try { this.audioSource.stop(); } catch (e) {}
      this.audioSource = null;
    }
  };

  VoiceOutput.prototype._setStatus = function (status) {
    if (this.status !== status) {
      var old = this.status;
      this.status = status;
      this.onStatusChange(old, status);
    }
  };

  VoiceOutput.prototype.destroy = function () {
    this.stop();
    if (this.audioContext) {
      this.audioContext.close();
      this.audioContext = null;
    }
  };

  // 暴露到全局
  global.VoiceOutput = VoiceOutput;

})(typeof window !== 'undefined' ? window : this);
