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

uniform sampler2D InputTexture;
uniform float vibranceValue; // -100 to 100

const vec3 luminanceWeight = vec3(0.2126, 0.7152, 0.0722);

// Check if a color is potentially a skin tone (approximate)
float skinToneLikelihood(vec3 color) {
    // Simple skin tone detection - check if in common skin tone range
    // Based on normalized r/g ratio in RGB space
    float total = color.r + color.g + color.b;
    if (total < 0.001) return 0.0;
    
    vec3 normalized = color / total;
    
    // Detect skin tones based on red-green ratio and absolute red value
    bool redEnough = normalized.r > 0.35;
    bool redGreenRatio = normalized.r / normalized.g > 1.1 && normalized.r / normalized.g < 2.0;
    bool notTooBlue = normalized.b < 0.4;
    
    return (redEnough && redGreenRatio && notTooBlue) ? 1.0 - pow(normalized.b * 1.5, 2.0) : 0.0;
}

vec3 applyVibrance(vec3 color, float vibrance) {
    float vibAmount = vibrance / 100.0; // Map to -1..1
    
    // Calculate better saturation
    float luma = dot(color, luminanceWeight);
    vec3 chroma = max(color - luma, 0.0);
    float sat = length(chroma) / (luma + 0.001);
    
    // Get skin tone protection factor
    float skinFactor = skinToneLikelihood(color);
    
    // Calculate adjustment strength based on current saturation
    // Less effect on already highly saturated colors
    float satWeight = 1.0 - smoothstep(0.2, 0.8, sat);
    
    // Apply less vibrance to skin tones
    float adjustmentFactor = satWeight * (1.0 - skinFactor * 0.7);
    
    // Create non-linear response curve for natural-looking adjustment
    float strength = vibAmount > 0.0 
        ? vibAmount * (1.0 - pow(sat, 2.0)) // Positive vibrance
        : vibAmount; // Negative vibrance (desaturation)
    
    // Fine-tune the saturation component-wise to preserve color relationships
    vec3 satColor = color;
    if (abs(vibAmount) > 0.001) {
        // Get distance from gray for each channel
        vec3 dist = color - luma;
        
        // Adjust distance based on vibrance
        dist *= (1.0 + strength * adjustmentFactor);
        
        // Rebuild color from luma + adjusted chroma
        satColor = luma + dist;
        
        // Preserve color ratios for extreme adjustments
        if (vibAmount > 0.5) {
            float maxComponent = max(satColor.r, max(satColor.g, satColor.b));
            if (maxComponent > 1.0) {
                float scale = min(1.0 / maxComponent, 2.0); // Limit scaling
                satColor = luma + (satColor - luma) * scale;
            }
        }
    }
    
    return satColor;
}

void main() {
    vec4 color = texture(InputTexture, TexCoord);
    color.rgb = applyVibrance(color.rgb, vibranceValue);
    FragColor = vec4(max(color.rgb, vec3(0.0)), color.a);
}