package dev.adriankuta.visualizer

import android.media.audiofx.Visualizer
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.State
import androidx.compose.ui.graphics.Color
import dev.adriankuta.visualizer.domain.SoundToColorMapper
import dev.adriankuta.visualizer.domain.SoundToColorMapperFactory
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import timber.log.Timber

/**
 * Interface for audio visualization functionality.
 * Follows Interface Segregation Principle.
 */
interface AudioVisualizerService {
    val currentColor: State<Color>
    val isActive: State<Boolean>
    
    fun start()
    fun stop()
    fun release()
}

/**
 * Implementation of AudioVisualizerService using Android's Visualizer API.
 * 
 * Follows Single Responsibility Principle by focusing on audio visualization.
 * Uses Dependency Injection for the sound-to-color mapper.
 */
class AndroidAudioVisualizer(
    private val soundToColorMapper: SoundToColorMapper = SoundToColorMapperFactory.createDefault(),
    private val coroutineScope: CoroutineScope = CoroutineScope(Dispatchers.Main)
) : AudioVisualizerService {
    
    companion object {
        private const val SAMPLING_RATE = 16000 // Hz
        private const val CAPTURE_SIZE = 1024 // Window size for audio capture
    }
    
    private var visualizer: Visualizer? = null
    private var processingJob: Job? = null
    
    private val _currentColor = mutableStateOf(Color.Black)
    override val currentColor: State<Color> = _currentColor
    
    private val _isActive = mutableStateOf(false)
    override val isActive: State<Boolean> = _isActive
    
    override fun start() {
        try {
            // Initialize visualizer with audio session ID 0 (output mix)
            visualizer = Visualizer(0).apply {
                captureSize = CAPTURE_SIZE
                
                // Set up waveform data listener
                setDataCaptureListener(
                    object : Visualizer.OnDataCaptureListener {
                        override fun onWaveFormDataCapture(
                            visualizer: Visualizer?,
                            waveform: ByteArray?,
                            samplingRate: Int
                        ) {
                            waveform?.let { processWaveform(it) }
                        }
                        
                        override fun onFftDataCapture(
                            visualizer: Visualizer?,
                            fft: ByteArray?,
                            samplingRate: Int
                        ) {
                            // Not used in this implementation
                        }
                    },
                    Visualizer.getMaxCaptureRate() / 2, // Capture rate
                    true, // Waveform
                    false // FFT
                )
                
                enabled = true
            }
            
            _isActive.value = true
            Timber.d("AudioVisualizer started successfully")
            
        } catch (e: Exception) {
            Timber.e(e, "Failed to start AudioVisualizer")
            _isActive.value = false
        }
    }
    
    override fun stop() {
        try {
            visualizer?.enabled = false
            processingJob?.cancel()
            _isActive.value = false
            Timber.d("AudioVisualizer stopped")
        } catch (e: Exception) {
            Timber.e(e, "Error stopping AudioVisualizer")
        }
    }
    
    override fun release() {
        stop()
        try {
            visualizer?.release()
            visualizer = null
            soundToColorMapper.reset()
            Timber.d("AudioVisualizer released")
        } catch (e: Exception) {
            Timber.e(e, "Error releasing AudioVisualizer")
        }
    }
    
    private fun processWaveform(waveform: ByteArray) {
        processingJob?.cancel()
        processingJob = coroutineScope.launch(Dispatchers.Default) {
            try {
                val color = soundToColorMapper.mapSoundToColor(waveform)
                
                // Update UI on main thread
                launch(Dispatchers.Main) {
                    _currentColor.value = color
                }
            } catch (e: Exception) {
                Timber.e(e, "Error processing waveform")
            }
        }
    }
}

/**
 * Factory for creating AudioVisualizerService instances.
 * Follows Factory Pattern and makes testing easier.
 */
object AudioVisualizerFactory {
    
    /**
     * Creates a default Android audio visualizer.
     */
    fun createDefault(coroutineScope: CoroutineScope): AudioVisualizerService {
        return AndroidAudioVisualizer(
            soundToColorMapper = SoundToColorMapperFactory.createDefault(),
            coroutineScope = coroutineScope
        )
    }
    
    /**
     * Creates an Android audio visualizer with custom mapper.
     */
    fun create(
        soundToColorMapper: SoundToColorMapper,
        coroutineScope: CoroutineScope
    ): AudioVisualizerService {
        return AndroidAudioVisualizer(soundToColorMapper, coroutineScope)
    }
}