import kotlin.math.sqrt

data class HSL(
// in Python code, the HSL values were in range 0 - 1

    val hue: Float,
    val saturation: Float,
    val lightness: Float
) {
    fun toRgb(): Triple<Int, Int, Int> {
        val (r, g, b) = hlsToRgb(hue / 360, lightness, saturation) // Convert HSL to RGB
        return Triple((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt())
    }

    private fun hlsToRgb(h: Float, l: Float, s: Float): Triple<Float, Float, Float> {
        val r: Float
        val g: Float
        val b: Float

        if (s == 0f) {
            // Achromatic (gray)
            r = l
            g = l
            b = l
        } else {
            val q = if (l < 0.5) l * (1 + s) else l + s - l * s
            val p = 2 * l - q

            r = hueToRgb(p, q, h + 1 / 3)
            g = hueToRgb(p, q, h)
            b = hueToRgb(p, q, h - 1 / 3)
        }

        return Triple(r, g, b)
    }

    private fun hueToRgb(p: Float, q: Float, t: Float): Float {
        var tTemp = t
        if (tTemp < 0) tTemp += 1
        if (tTemp > 1) tTemp -= 1
        return when {
            tTemp < 1 / 6 -> p + (q - p) * 6 * tTemp
            tTemp < 1 / 2 -> q
            tTemp < 2 / 3 -> p + (q - p) * (2 / 3 - tTemp) * 6
            else -> p
        }
    }
}

// copied from Adrian's code, so this probably redundant here
private fun rms(bytes: ByteArray): Double {
    if (bytes.isEmpty()) return 0.0
    var sum = 0.0
    for (b in bytes) {
        val centered = (b.toInt() and 0xFF) - 128
        sum += centered * centered
    }
    return kotlin.math.sqrt(sum / bytes.size)
}


// not sure whether the rmsMax, movingAverage, and hslColor should be passed as parameter, therefore I used  "...", in Python they were all: self.rms_max, ... so I could access them directly
fun soundToColor( ... ) {
	// Time domain processing, adjustable maximum of energy (we need ratio, as we do not have given maximum)
    	
	// calculate RMS value for one current frame, actualize value of RMS maximum
	val tmpRms = rms(wf)		// variable "wf" - waveform, I saw it Adrian's code
	if (tmpRms > rmsMax) {
		rmsMax = tmpRms
	}
	energyRatio = tmpRms / rmsMax
    adjLightness = movingAverage.process(energyRatio)
	hslColor.lightness = adjLightness
	val rgbColor = hslColor.toRgb()
	return rgbColor
}



// predefine values for soundToColor method
val movingAverage = MovingAverage(windowSize = 7)	// object for calculation of moving average, this should stay the same during the run of application
rmsMax = 0.0		// to store the value of current maximum of RMS, this might be changed in every call of method (every loop)
val hslColor = HSL(hue = 0f, saturation = 1f, value = 0f)	// to store the values for current color, value will change every loop


// I can only gues, but I can imagine that the definitioin of variables (movingAverage, rmsMax, hslColor) can be defined
// somewhere at higher level of application, maybe VisualizerScreen.
// Somewhere, where the loop that takes data for waveform, where the data can be passed to soundToColor.
//
// And as I do not know Kotlin, I am not able to tell how it should be there.
// Then, the method soundToColor might be defined (implemented) in MetricsSection, with the rest of the code too.
// Or is it for separate file?
//
// I can only gues how it will work. In Python, the settigns of audio processing was:
// sampling_rate = 16000 # Hz, sampling frequency
// window_size = 1024
// moving averate size = 7
//
// I think that, when the window size (or sampling rate) is different we will need to find new value for moving average