// ============================================================================
// FOG EFFECTS
// ============================================================================
#ifndef FOG_GLSL
#define FOG_GLSL

#include "/lib/settings.glsl"
#include "/lib/uniforms.glsl"
#include "/lib/sky.glsl" 
#include "/lib/water.glsl"

void applyFog(
    float distance,
    vec3 worldPos,
    vec3 worldViewDir,
    vec3 worldSunDir,
    float skyLightCurve,
    float rainStrength,
    float far,
    vec3 lightSunColor,
    out vec3 finalFogColor,
    out float finalFogFactor,
    out float borderFogFactorOut
) {
    // Handle underwater fog overrides.
    if (isEyeInWater == 1) {
        applyUnderwaterFog(distance, worldPos, worldViewDir, worldSunDir, skyLightCurve, rainStrength, lightSunColor, finalFogColor, finalFogFactor);
        
        #if ENABLE_BORDER_FOG == 1
            float borderEnd = far * float(UNDERWATER_BORDER_FOG_END);
            float borderProgress = smoothstep(0.0, borderEnd, distance);

            if (borderProgress > 0.001) {
                borderProgress = pow(borderProgress, float(UNDERWATER_BORDER_FOG_FALLOFF));
                float borderFogFactor = 1.0 - borderProgress;
                borderFogFactorOut = borderFogFactor;

                finalFogFactor = min(finalFogFactor, borderFogFactor);
                vec3 bgFogColor;
                float dummyFactor;
                applyUnderwaterFog(far * 2.0, worldPos, worldViewDir, worldSunDir, 1.0, rainStrength, lightSunColor, bgFogColor, dummyFactor);
                finalFogColor = mix(finalFogColor, bgFogColor, borderProgress);
            } else {
                borderFogFactorOut = 1.0;
            }
        #else
            borderFogFactorOut = 1.0; 
        #endif
        return; 
    }

    // Fetch base sky colors.
    vec3 zenithColor, extFogColor;
    getSkyColors(worldViewDir, worldSunDir, rainStrength, zenithColor, extFogColor);

    // ========================================================================
    // 1. TRUE VOLUMETRIC SKY COLOR
    // Recreate the exact sky dome and sun glow used by the Border Fog.
    // ========================================================================
    float skyHeight = max(worldViewDir.y, 0.0);
    float skyGradient = pow(skyHeight, float(SKY_GRADIENT));
    vec3 trueSkyColor = mix(extFogColor, zenithColor, skyGradient);
    
    float sunDotFog = dot(worldViewDir, worldSunDir);
    float skyDim = mix(1.0, 1.0 - float(SKY_RAIN_COVERAGE), rainStrength);
    float sunGlowSky = pow(max(sunDotFog, 0.0), float(SUN_GLOW_SPREAD)) * float(SUN_GLOW_POWER) * skyDim;
    
    trueSkyColor += (lightSunColor * sunGlowSky);
    
    // ========================================================================
    // 2. BASE FOG COLOR ADJUSTMENTS
    // Apply saturation and brightness controls independently from border fog.
    // ========================================================================
    float fogLuma = dot(trueSkyColor, vec3(0.299, 0.587, 0.114));
    extFogColor = mix(vec3(fogLuma), trueSkyColor, float(FOG_SATURATION));
    extFogColor *= float(FOG_BRIGHTNESS);

    // ========================================================================
    // 3. UNIFIED BASE FOG FACTORS
    // Fog is identical everywhere, above and below ground.
    // ========================================================================
    float heightFogMask = smoothstep(120.0, 60.0, worldPos.y);
    float dynamicDensity = float(FOG_DENSITY) * mix(1.0, float(FOG_RAIN_MULTIPLIER), rainStrength) * mix(0.2, 1.0, heightFogMask);
    float currentFalloff = mix(float(FOG_FALLOFF), float(FOG_RAIN_FALLOFF), rainStrength);
    
    finalFogFactor = clamp(exp(-pow(distance * dynamicDensity, currentFalloff)), 0.0, 1.0);
    finalFogColor  = extFogColor;

    // ========================================================================
    // 4. BORDER FOG (For normal chunks)
    // ========================================================================
    #if ENABLE_BORDER_FOG == 1
        float currentBorderStart = mix(float(BORDER_FOG_START), float(BORDER_FOG_RAIN_START), rainStrength);
        float currentBorderFalloff = mix(float(BORDER_FOG_FALLOFF), float(BORDER_FOG_RAIN_FALLOFF), rainStrength);

        float borderStart = far * currentBorderStart;
        float borderEnd   = far * float(BORDER_FOG_END);
        float borderProgress = clamp((distance - borderStart) / max(borderEnd - borderStart, 0.001), 0.0, 1.0);

        if (borderProgress > 0.001) {
            borderProgress = pow(borderProgress, currentBorderFalloff);
            float borderFogFactor = 1.0 - borderProgress;
            borderFogFactorOut = borderFogFactor;

            // Border fog matches the unmodified true sky color.
            finalFogColor = mix(trueSkyColor, finalFogColor, borderFogFactor);
            finalFogFactor = min(finalFogFactor, borderFogFactor);
        } else {
            borderFogFactorOut = 1.0;
        }
    #else
        borderFogFactorOut = 1.0;
    #endif
}

#endif