var g = Object.defineProperty;
var f = (h, t, e) => t in h ? g(h, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : h[t] = e;
var i = (h, t, e) => f(h, typeof t != "symbol" ? t + "" : t, e);
import { A as C, e as m, a as c, l as r } from "./index-bbc7bE-q.js";
class A {
  constructor(t) {
    // AudioContext is managed internally
    i(this, "audioContext", null);
    i(this, "sampleRate");
    i(this, "channelCount");
    i(this, "debug");
    // Session-level state
    i(this, "sessionId");
    i(this, "sessionStartTime", 0);
    // AudioContext time when session started
    i(this, "pausedTimeOffset", 0);
    // Accumulated paused time
    i(this, "pausedAt", 0);
    // Time when paused
    i(this, "scheduledTime", 0);
    // Next chunk schedule time in AudioContext time
    // Playback state
    i(this, "isPlaying", !1);
    i(this, "isPaused", !1);
    i(this, "autoStartEnabled", !0);
    // Control whether to auto-start when buffer is ready
    // Audio buffer queue
    i(this, "audioChunks", []);
    i(this, "scheduledChunks", 0);
    // Number of chunks already scheduled
    i(this, "activeSources", []);
    // Event callbacks
    i(this, "onEndedCallback");
    this.sessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, this.sampleRate = (t == null ? void 0 : t.sampleRate) ?? C.audio.sampleRate, this.channelCount = (t == null ? void 0 : t.channelCount) ?? 1, this.debug = (t == null ? void 0 : t.debug) ?? !1;
  }
  /**
   * Initialize audio context (create and ensure it's ready)
   */
  async initialize() {
    if (!this.audioContext)
      try {
        this.audioContext = new AudioContext({
          sampleRate: this.sampleRate
        }), this.audioContext.state === "suspended" && await this.audioContext.resume(), this.log("AudioContext initialized", {
          sessionId: this.sessionId,
          sampleRate: this.audioContext.sampleRate,
          state: this.audioContext.state
        });
      } catch (t) {
        const e = m(t);
        throw c.logEvent("activeAudioSessionFailed", "warning", {
          sessionId: this.sessionId,
          reason: e
        }), r.error("Failed to initialize AudioContext:", e), t instanceof Error ? t : new Error(e);
      }
  }
  /**
   * Add audio chunk (16-bit PCM)
   */
  addChunk(t, e = !1) {
    if (!this.audioContext) {
      r.error("AudioContext not initialized");
      return;
    }
    this.audioChunks.push({ data: t, isLast: e }), this.log(`Added chunk ${this.audioChunks.length}`, {
      size: t.length,
      totalChunks: this.audioChunks.length,
      isLast: e,
      isPlaying: this.isPlaying,
      scheduledChunks: this.scheduledChunks
    }), !this.isPlaying && this.autoStartEnabled && this.audioChunks.length > 0 ? (this.log("[StreamingAudioPlayer] Auto-starting playback from addChunk"), this.startPlayback()) : this.isPlaying ? (this.log("[StreamingAudioPlayer] Already playing, scheduling next chunk"), this.scheduleNextChunk()) : this.log("[StreamingAudioPlayer] Not playing and no chunks, waiting for more chunks");
  }
  /**
   * Start new session (stop current and start fresh)
   */
  async startNewSession(t) {
    this.stop(), this.sessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, this.audioChunks = [], this.scheduledChunks = 0, this.pausedTimeOffset = 0, this.pausedAt = 0, this.log("Starting new session", {
      chunks: t.length
    });
    for (const e of t)
      this.addChunk(e.data, e.isLast);
  }
  /**
   * Start playback
   */
  startPlayback() {
    if (!this.audioContext) {
      this.log("[StreamingAudioPlayer] Cannot start playback: AudioContext not initialized");
      return;
    }
    if (this.isPlaying) {
      this.log("[StreamingAudioPlayer] Cannot start playback: Already playing");
      return;
    }
    this.isPlaying = !0, this.sessionStartTime = this.audioContext.currentTime, this.scheduledTime = this.sessionStartTime, this.log("[StreamingAudioPlayer] Starting playback", {
      sessionStartTime: this.sessionStartTime,
      bufferedChunks: this.audioChunks.length,
      scheduledChunks: this.scheduledChunks,
      activeSources: this.activeSources.length
    }), this.scheduleAllChunks();
  }
  /**
   * Schedule all pending chunks
   */
  scheduleAllChunks() {
    for (; this.scheduledChunks < this.audioChunks.length; )
      this.scheduleNextChunk();
  }
  /**
   * Schedule next audio chunk
   */
  scheduleNextChunk() {
    if (!this.audioContext) {
      this.log("[StreamingAudioPlayer] Cannot schedule chunk: AudioContext not initialized");
      return;
    }
    if (!this.isPlaying) {
      this.log("[StreamingAudioPlayer] Cannot schedule chunk: Not playing");
      return;
    }
    const t = this.scheduledChunks;
    if (t >= this.audioChunks.length) {
      this.log(`[StreamingAudioPlayer] No more chunks to schedule (chunkIndex: ${t}, totalChunks: ${this.audioChunks.length})`);
      return;
    }
    const e = this.audioChunks[t];
    if (e.data.length === 0 && !e.isLast) {
      this.scheduledChunks++;
      return;
    }
    const l = e.data, o = e.isLast, a = this.pcmToAudioBuffer(l);
    if (!a) {
      r.error("Failed to create AudioBuffer from PCM data"), c.logEvent("character_player", "error", {
        sessionId: this.sessionId,
        event: "audio_buffer_creation_failed"
      });
      return;
    }
    try {
      const s = this.audioContext.createBufferSource();
      s.buffer = a, s.connect(this.audioContext.destination), s.start(this.scheduledTime), this.activeSources.push(s), s.onended = () => {
        const u = this.activeSources.indexOf(s);
        u >= 0 && this.activeSources.splice(u, 1), o && this.activeSources.length === 0 && (this.log("Last audio chunk ended, marking playback as ended"), this.markEnded());
      }, this.scheduledTime += a.duration, this.scheduledChunks++, this.log(`[StreamingAudioPlayer] Scheduled chunk ${t + 1}/${this.audioChunks.length}`, {
        startTime: this.scheduledTime - a.duration,
        duration: a.duration,
        nextScheduleTime: this.scheduledTime,
        isLast: o,
        activeSources: this.activeSources.length
      });
    } catch (s) {
      r.errorWithError("Failed to schedule audio chunk:", s), c.logEvent("character_player", "error", {
        sessionId: this.sessionId,
        event: "schedule_chunk_failed",
        reason: s instanceof Error ? s.message : String(s)
      });
    }
  }
  /**
   * Convert PCM data to AudioBuffer
   * Input: 16-bit PCM (int16), Output: AudioBuffer (float32 [-1, 1])
   */
  pcmToAudioBuffer(t) {
    if (!this.audioContext)
      return null;
    if (t.length === 0) {
      const u = Math.floor(this.sampleRate * 0.01), n = this.audioContext.createBuffer(
        this.channelCount,
        u,
        this.sampleRate
      );
      for (let d = 0; d < this.channelCount; d++)
        n.getChannelData(d).fill(0);
      return n;
    }
    const e = new Uint8Array(t), l = new Int16Array(e.buffer, 0, e.length / 2), o = l.length / this.channelCount, a = this.audioContext.createBuffer(
      this.channelCount,
      o,
      this.sampleRate
    );
    for (let s = 0; s < this.channelCount; s++) {
      const u = a.getChannelData(s);
      for (let n = 0; n < o; n++) {
        const d = n * this.channelCount + s;
        u[n] = l[d] / 32768;
      }
    }
    return a;
  }
  /**
   * Get current playback time (seconds)
   */
  getCurrentTime() {
    if (!this.audioContext || !this.isPlaying)
      return 0;
    if (this.isPaused)
      return this.pausedAt;
    const e = this.audioContext.currentTime - this.sessionStartTime - this.pausedTimeOffset;
    return Math.max(0, e);
  }
  /**
   * Pause playback
   */
  pause() {
    !this.isPlaying || this.isPaused || (this.isPaused = !0, this.pausedAt = this.getCurrentTime(), this.log("Playback paused", {
      pausedAt: this.pausedAt
    }));
  }
  /**
   * Resume playback
   */
  async resume() {
    if (!this.isPaused || !this.audioContext)
      return;
    const t = this.audioContext.currentTime - (this.sessionStartTime + this.pausedAt);
    this.pausedTimeOffset += t, this.isPaused = !1, this.log("Playback resumed", {
      pauseDuration: t,
      totalPausedOffset: this.pausedTimeOffset
    });
  }
  /**
   * Stop playback
   */
  stop() {
    if (this.audioContext) {
      this.isPlaying = !1, this.isPaused = !1, this.sessionStartTime = 0, this.scheduledTime = 0;
      for (const t of this.activeSources) {
        t.onended = null;
        try {
          t.stop(0);
        } catch {
        }
        try {
          t.disconnect();
        } catch {
        }
      }
      this.activeSources = [], this.audioChunks = [], this.scheduledChunks = 0, this.log("[StreamingAudioPlayer] Playback stopped, state reset");
    }
  }
  /**
   * Enable or disable auto-start (for delayed start scenarios)
   */
  setAutoStart(t) {
    this.autoStartEnabled = t, this.log(`Auto-start ${t ? "enabled" : "disabled"}`);
  }
  /**
   * Start playback manually (for delayed start scenarios)
   * This allows starting playback after transition animation completes
   */
  play() {
    this.isPlaying || (this.autoStartEnabled = !0, this.startPlayback());
  }
  /**
   * Mark playback as ended
   */
  markEnded() {
    var t;
    this.log("Playback ended"), this.isPlaying = !1, (t = this.onEndedCallback) == null || t.call(this);
  }
  /**
   * Set ended callback
   */
  onEnded(t) {
    this.onEndedCallback = t;
  }
  /**
   * Check if playing
   */
  isPlayingNow() {
    return this.isPlaying && !this.isPaused;
  }
  /**
   * Get total duration of buffered audio
   */
  getBufferedDuration() {
    if (!this.audioContext)
      return 0;
    let t = 0;
    for (const e of this.audioChunks)
      t += e.data.length / 2 / this.channelCount;
    return t / this.sampleRate;
  }
  /**
   * Get remaining duration (buffered - played) in seconds
   */
  getRemainingDuration() {
    const t = this.getBufferedDuration(), e = this.getCurrentTime();
    return Math.max(0, t - e);
  }
  /**
   * Dispose and cleanup
   */
  dispose() {
    this.stop(), this.audioContext && (this.audioContext.close(), this.audioContext = null), this.audioChunks = [], this.scheduledChunks = 0, this.sessionStartTime = 0, this.pausedTimeOffset = 0, this.pausedAt = 0, this.scheduledTime = 0, this.onEndedCallback = void 0, this.log("StreamingAudioPlayer disposed");
  }
  /**
   * Flush buffered audio
   * - hard: stops all playing sources and clears all chunks
   * - soft (default): clears UNSCHEDULED chunks only
   */
  flush(t) {
    if ((t == null ? void 0 : t.hard) === !0) {
      this.stop(), this.audioChunks = [], this.scheduledChunks = 0, this.sessionStartTime = 0, this.pausedAt = 0, this.scheduledTime = 0, this.log("Flushed (hard)");
      return;
    }
    this.scheduledChunks < this.audioChunks.length && this.audioChunks.splice(this.scheduledChunks), this.log("Flushed (soft)", { remainingScheduled: this.scheduledChunks });
  }
  /**
   * Debug logging
   */
  log(t, e) {
    this.debug && r.log(`[StreamingAudioPlayer] ${t}`, e || "");
  }
}
export {
  A as StreamingAudioPlayer
};
//# sourceMappingURL=StreamingAudioPlayer-8Dz_aHCW.js.map
