package dev.adriankuta.visualizer.domain

import androidx.compose.ui.graphics.Color
import dev.adriankuta.visualizer.HSL
import dev.adriankuta.visualizer.MovingAverage
import dev.adriankuta.visualizer.calculateRms

/**
 * Interface for mapping sound data to colors.
 * Follows the Interface Segregation Principle by defining a focused contract.
 */
interface SoundToColorMapper {
    /**
     * Maps audio waveform data to a color.
     * 
     * @param waveform Audio waveform data as byte array
     * @return Compose Color representing the mapped sound
     */
    fun mapSoundToColor(waveform: ByteArray): Color
    
    /**
     * Resets the internal state of the mapper.
     */
    fun reset()
}

/**
 * Default implementation of SoundToColorMapper that uses HSL color space
 * and moving average for smooth color transitions.
 * 
 * Follows Single Responsibility Principle by focusing on sound-to-color mapping.
 * Follows Dependency Inversion Principle by depending on abstractions.
 */
class HSLSoundToColorMapper(
    private val baseHue: Float = 0f, // Blue hue as default
    private val saturation: Float = 1f,
    private val movingAverageWindowSize: Int = 1
) : SoundToColorMapper {
    
    private val movingAverage = MovingAverage(movingAverageWindowSize)
    private var rmsMax = 0.0
    
    override fun mapSoundToColor(waveform: ByteArray): Color {
        // Calculate RMS value for current frame
        val currentRms = calculateRms(waveform)
        
        // Update maximum RMS value for normalization
        if (currentRms > rmsMax) {
            rmsMax = currentRms
        }
        
        // Calculate energy ratio (0-1)
        val energyRatio = if (rmsMax > 0) currentRms / rmsMax else 0.0
        
        // Apply moving average for smooth transitions
        val adjustedLightness = movingAverage.process(energyRatio)
        
        // Create HSL color and convert to Compose Color
        val hslColor = HSL(
            hue = baseHue,
            saturation = saturation,
            lightness = adjustedLightness.toFloat().coerceIn(0f, 1f)
        )
        
        return hslColor.toComposeColor()
    }
    
    override fun reset() {
        movingAverage.reset()
        rmsMax = 0.0
    }
}

/**
 * Factory for creating SoundToColorMapper instances.
 * Follows the Factory Pattern and Open/Closed Principle.
 */
object SoundToColorMapperFactory {
    
    /**
     * Creates a default HSL-based sound to color mapper.
     */
    fun createDefault(): SoundToColorMapper = HSLSoundToColorMapper()
    
    /**
     * Creates an HSL-based sound to color mapper with custom parameters.
     * 
     * @param baseHue The base hue for the color (0-360)
     * @param saturation The saturation level (0-1)
     * @param movingAverageWindowSize Window size for moving average smoothing
     */
    fun createHSLMapper(
        baseHue: Float = 240f,
        saturation: Float = 1f,
        movingAverageWindowSize: Int = 7
    ): SoundToColorMapper = HSLSoundToColorMapper(baseHue, saturation, movingAverageWindowSize)
}