// composables/useRealtimeRecorder.js
import {
    ref
} from 'vue'

export function useRealtimeRecorder(wsUrl) {
    const isRecording = ref(false)
    const recognizedText = ref('')

    let audioContext = null
    let audioWorkletNode = null
    let sourceNode = null
    let socket = null

    const startRecording = async () => {
        const stream = await navigator.mediaDevices.getUserMedia({
            audio: true
        })

        audioContext = new(window.AudioContext || window.webkitAudioContext)()
        const processorCode = `
      class RecorderProcessor extends AudioWorkletProcessor {
        constructor() {
          super()
          this.buffer = []
          this.inputSampleRate = sampleRate
          this.targetSampleRate = 16000
        }

        process(inputs) {
          const input = inputs[0][0]
          if (!input) return true
          this.buffer.push(...input)
          const requiredSamples = this.inputSampleRate / 10 // 100ms

          if (this.buffer.length >= requiredSamples) {
            const resampled = this.downsample(this.buffer, this.inputSampleRate, this.targetSampleRate)
            const int16Buffer = this.floatTo16BitPCM(resampled)
            this.port.postMessage(int16Buffer)
            this.buffer = []
          }
          return true
        }

        downsample(buffer, inRate, outRate) {
          if (outRate === inRate) return buffer
          const ratio = inRate / outRate
          const len = Math.floor(buffer.length / ratio)
          const result = new Float32Array(len)
          for (let i = 0; i < len; i++) {
            const start = Math.floor(i * ratio)
            const end = Math.floor((i + 1) * ratio)
            let sum = 0
            for (let j = start; j < end && j < buffer.length; j++) sum += buffer[j]
            result[i] = sum / (end - start)
          }
          return result
        }

        floatTo16BitPCM(input) {
          const output = new Int16Array(input.length)
          for (let i = 0; i < input.length; i++) {
            const s = Math.max(-1, Math.min(1, input[i]))
            output[i] = s < 0 ? s * 0x8000 : s * 0x7FFF
          }
          return output.buffer
        }
      }
      registerProcessor('recorder-processor', RecorderProcessor)
    `
        const blob = new Blob([processorCode], {
            type: 'application/javascript'
        })
        const blobUrl = URL.createObjectURL(blob)

        await audioContext.audioWorklet.addModule(blobUrl)

        socket = new WebSocket(wsUrl)
        socket.onmessage = (e) => {
            recognizedText.value = e.data
        }

        sourceNode = audioContext.createMediaStreamSource(stream)
        audioWorkletNode = new AudioWorkletNode(audioContext, 'recorder-processor')

        audioWorkletNode.port.onmessage = (e) => {
            const audioData = e.data
            if (socket && socket.readyState === WebSocket.OPEN) {
                socket.send(audioData)
            }
        }

        sourceNode.connect(audioWorkletNode)
        audioWorkletNode.connect(audioContext.destination)

        isRecording.value = true
    }

    const stopRecording = () => {
        sourceNode?.disconnect()
        audioWorkletNode?.disconnect()
        audioContext?.close()

        if (socket?.readyState === WebSocket.OPEN) {
            socket.send('[end]')
            socket.close()
        }

        audioContext = null
        sourceNode = null
        audioWorkletNode = null
        socket = null

        isRecording.value = false
    }

    const cancelRecording = () => {
        stopRecording()
        recognizedText.value = ''
    }

    return {
        isRecording,
        recognizedText,
        startRecording,
        stopRecording,
        cancelRecording
    }
}