import Foundation
import Metal
import simd

class AuraRenderPass {
    private var lastAColor: ADVector3 = .zero
    private var lastBColor: ADVector3 = .zero
    private var lastCColor: ADVector3 = .zero

    private var gpu: MTLDevice? {
        return Adamantium.sharedDevice
    }

    func setColorSet(_ triColorSet: SunoTriColorSet, deltaTime: TimeInterval) {
        let floatDeltaTime = Float(deltaTime)
        let targetColorA = triColorSet.floatColorA
        let targetColorB = triColorSet.floatColorB
        let targetColorC = triColorSet.floatColorC

        let aR = simd_mix(lastAColor.x, targetColorA.x, floatDeltaTime)
        let aG = simd_mix(lastAColor.y, targetColorA.y, floatDeltaTime)
        let aB = simd_mix(lastAColor.z, targetColorA.z, floatDeltaTime)
        lastAColor = simd_float3(x: aR, y: aG, z: aB)

        let bR = simd_mix(lastBColor.x, targetColorB.x, floatDeltaTime)
        let bG = simd_mix(lastBColor.y, targetColorB.y, floatDeltaTime)
        let bB = simd_mix(lastBColor.z, targetColorB.z, floatDeltaTime)
        lastBColor = simd_float3(x: bR, y: bG, z: bB)

        let cR = simd_mix(lastCColor.x, targetColorC.x, floatDeltaTime)
        let cG = simd_mix(lastCColor.y, targetColorC.y, floatDeltaTime)
        let cB = simd_mix(lastCColor.z, targetColorC.z, floatDeltaTime)
        lastCColor = simd_float3(x: cR, y: cG, z: cB)
    }

    func updateUniforms(_ deltaTime: TimeInterval) {
        setColorSet(.yellowOrangeBlue, deltaTime: deltaTime)
    }

    func renderAura(
        encoder: MTLRenderCommandEncoder,
        drawableSize: CGSize,
        startingTime: Date
    ) {
        var size: ADVector2 {
            return ADVector2(
                x: Float(drawableSize.width),
                y: Float(drawableSize.height)
            )
        }

        let timeElapsed = ADFloat(Date.now.timeIntervalSince(startingTime))
        let grainElapsedTime = timeElapsed * 0.01

        let mixPointStart: ADFloat = -0.2
        let mixPointBackground: ADFloat = -0.1
        let mixPointBackgroundA: ADFloat = 0.0
        let mixPointAB: ADFloat = 0.2
        let mixPointBC: ADFloat = 0.3
        let mixPointEnd: ADFloat = 0.8

        let noiseRenderable = GradientToAuraRenderable()
        noiseRenderable.config = .init(
            displaySize: size,
            grainNoiseZ: grainElapsedTime,
            grainNoiseScale: 5.0,
            backgroundColor: SunoColorPalette.backgroundDotCom.floatThree,
            colorA: lastAColor,
            colorB: lastBColor,
            colorC: lastCColor,
            mixPointStart: mixPointStart,
            mixPointBackground: mixPointBackground,
            mixPointBackgroundA: mixPointBackgroundA,
            mixPointAB: mixPointAB,
            mixPointBC: mixPointBC,
            mixPointEnd: mixPointEnd
        )

        noiseRenderable.render(encoder: encoder)
    }
}
