#version 330 core
out vec4 FragColor;
in vec2 TexCoord;

uniform sampler2D InputTexture;
uniform float saturationValue; // -100 (grayscale) to 100 (double sat)

// Perceptual luminance weights (Rec. 709)
const vec3 luminanceWeight = vec3(0.2126, 0.7152, 0.0722);

vec3 applySaturation(vec3 color, float saturation) {
    // Get original luminance
    float lum = dot(color, luminanceWeight);
    
    // Skip processing for very dark or very bright pixels
    if (lum < 0.001 || lum > 0.999) return color;
    
    // Non-linear saturation response curve (more natural-looking)
    float factor;
    if (saturation >= 0.0) {
        // Positive saturation with highlight protection
        factor = 1.0 + (saturation / 100.0) * (1.0 - 0.3 * smoothstep(0.7, 1.0, lum));
    } else {
        // Negative saturation with shadow protection
        factor = 1.0 + (saturation / 100.0) * (1.0 - 0.1 * smoothstep(0.0, 0.2, lum));
    }
    
    // Apply saturation while preserving luminance
    vec3 adjusted = mix(vec3(lum), color, factor);
    
    // Ensure we maintain original luminance exactly
    float newLum = dot(adjusted, luminanceWeight);
    return adjusted * (lum / max(newLum, 0.001));
}

void main() {
    vec4 color = texture(InputTexture, TexCoord);
    
    // Apply saturation
    color.rgb = applySaturation(color.rgb, saturationValue);
    
    // Proper clamping to valid range
    FragColor = vec4(clamp(color.rgb, 0.0, 1.0), color.a);
}