import { getErrorMessage } from "@workshop/shared/errors"

export class StreamingResponse {
  private mediaRecorder?: MediaRecorder
  private mediaStream?: MediaStream
  private audioChunks: Blob[] = []
  private isRecording = false

  constructor(private onError: (error: string) => void) {}

  async start() {
    try {
      if (this.isRecording) return

      this.mediaStream = await navigator.mediaDevices.getUserMedia({
        audio: { echoCancellation: true, noiseSuppression: true, sampleRate: 16000 },
      })

      this.mediaRecorder = new MediaRecorder(this.mediaStream, { mimeType: "audio/webm" })
      this.audioChunks = []

      this.mediaRecorder.addEventListener("dataavailable", (event) => {
        if (event.data.size === 0) return
        console.log("Audio chunk received:", event.data.size, "bytes")
        this.audioChunks.push(event.data)
      })

      this.mediaRecorder.addEventListener("stop", async () => {
        this.mediaStream?.getTracks().forEach((track) => track.stop())
        this.isRecording = false
      })

      this.mediaRecorder.start(1000)
      this.isRecording = true
    } catch (error) {
      this.mediaRecorder?.stop()

      console.error("Error starting recording:", error)
      this.onError(`Failed to start recording: ${getErrorMessage(error)}`)
    }
  }

  async stop() {
    return new Promise<ReadableStreamDefaultReader<Uint8Array>>((resolve, reject) => {
      if (!this.mediaRecorder || !this.isRecording) {
        reject("No media recorder is active")
        return
      }

      this.mediaRecorder.addEventListener("stop", async () => {
        try {
          const audioBlob = new Blob(this.audioChunks, { type: "audio/webm" })
          const stream = await this.streamResponse(audioBlob)
          resolve(stream)
        } catch (error) {
          reject(`Failed to process audio stream: ${getErrorMessage(error)}`)
        }
      })

      this.mediaRecorder.stop()
    })
  }

  private async streamResponse(audioBlob: Blob) {
    const response = await fetch("/api/streamResponse", { method: "POST", body: audioBlob })

    if (!response.ok) {
      const errorText = await response.text()
      throw new Error(`Server error: ${response.status} - ${errorText}`)
    }

    return response.body!.getReader()
  }

  getIsRecording() {
    return this.isRecording
  }
}
