package dev.adriankuta.visualizer.data

import android.media.audiofx.Visualizer
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.filterIsInstance
import javax.inject.Inject

class AudioVisualizerImpl @Inject constructor(
    private val visualizer: Visualizer
) : AudioVisualizer {

    override fun start() {
        visualizer.enabled = true
    }

    override fun stop() {
        visualizer.enabled = false
    }

    override fun waveform(): Flow<WaveformFrame> =
        visualizerFlow()
            .filterIsInstance(WaveformFrame::class)

    override fun fft(): Flow<FftFrame> =
        visualizerFlow()
            .filterIsInstance(FftFrame::class)

    private fun visualizerFlow(): Flow<VisualizerFrame> = callbackFlow {
        val listener = object : Visualizer.OnDataCaptureListener {
            override fun onFftDataCapture(
                visualizer: Visualizer?,
                fft: ByteArray,
                samplingRate: Int
            ) {
                trySend(FftFrame(fft.copyOf()))
            }

            override fun onWaveFormDataCapture(
                visualizer: Visualizer?,
                waveform: ByteArray,
                samplingRate: Int
            ) {
                trySend(WaveformFrame(waveform.copyOf()))
            }
        }

        visualizer.setDataCaptureListener(
            listener,
            Visualizer.getMaxCaptureRate(),
            true,
            true
        )

        awaitClose {
            runCatching {
                visualizer.enabled = false
                visualizer.setDataCaptureListener(null, 0, false, false)
                visualizer.release()
            }
        }
    }
        .conflate()
}

sealed interface VisualizerFrame
data class WaveformFrame(
    val data: ByteArray,
) : VisualizerFrame

data class FftFrame(
    val data: ByteArray,
) : VisualizerFrame