package dev.adriankuta.visualizer

import android.media.audiofx.Visualizer

/**
 * Simple wrapper over Android Visualizer to capture global output mix (audio session 0).
 */
class VisualizerController(
    private val audioSessionId: Int = 0,
    private val onWaveform: (ByteArray) -> Unit,
    private val onFft: (ByteArray) -> Unit,
) {
    private var visualizer: Visualizer? = null

    /**
     * Starts capturing audio data via [Visualizer].
     *
     * Safe to call multiple times; subsequent calls are no-ops if already started.
     * If initialization fails (e.g., missing microphone permission or device restriction),
     * the controller performs cleanup and rethrows the underlying exception.
     */
    @Synchronized
    fun start() {
        if (visualizer != null) return
        try {
            val v = Visualizer(audioSessionId)
            // Use the maximum supported capture size for better resolution
            val captureSize = Visualizer.getCaptureSizeRange().let { it[1] }
            v.captureSize = captureSize
            val rate = Visualizer.getMaxCaptureRate() / 2 // decent rate
            v.setDataCaptureListener(object : Visualizer.OnDataCaptureListener {
                override fun onWaveFormDataCapture(
                    visualizer: Visualizer?,
                    waveform: ByteArray?,
                    samplingRate: Int
                ) {
                    if (waveform != null) onWaveform(waveform)
                }

                override fun onFftDataCapture(
                    visualizer: Visualizer?,
                    fft: ByteArray?,
                    samplingRate: Int
                ) {
                    if (fft != null) onFft(fft)
                }
            }, rate, true, true)
            v.enabled = true
            visualizer = v
        } catch (e: Throwable) {
            // If Visualizer cannot be initialized (e.g. permission or device restriction), ensure cleanup
            stop()
            throw e
        }
    }

    /**
     * Stops capturing audio data and releases the underlying [Visualizer].
     * Safe to call multiple times.
     */
    @Synchronized
    fun stop() {
        visualizer?.enabled = false
        visualizer?.release()
        visualizer = null
    }
}
