#include "/lib/all_the_libs.glsl"

uniform sampler2D gcolor;

// --- Distant Horizons Uniforms ---
#ifdef DISTANT_HORIZONS
uniform sampler2D dhDepthTex0;
#endif
// ---------------------------------

#define SHADOW_DISTORT_FACTOR 0.1
varying vec2 texcoord;

vec3 Distort(vec3 pos) {
    float factor = length(pos.xy) + SHADOW_DISTORT_FACTOR;
    return vec3(pos.xy / factor, pos.z * 0.5);
}

vec3 GetShadowColor(vec3 shadowCoord) {
    // If the shadow coordinate is outside the map (0.0 to 1.0), 
    // it means this point is outside the shadow distance.
    // We return 1.0 (full sun) to avoid glitches at the edge.
    if (shadowCoord.x < 0.0 || shadowCoord.x > 1.0 || 
        shadowCoord.y < 0.0 || shadowCoord.y > 1.0 || 
        shadowCoord.z < 0.0 || shadowCoord.z > 1.0) {
        return vec3(1.0);
    }

    float pixelSize = 1.0 / SHADOW_MAP_RESOLUTION; 
    float bias =0.00035;
    
    vec3 shadowTotal = vec3(0.0);

    // 3x3 Loop for Softness
    for(int x = -1; x <= 1; x++) {
        for(int y = -1; y <= 1; y++) {
            vec2 offset = vec2(x, y) * pixelSize;
            vec2 sampleCoord = shadowCoord.xy + offset;

            float depthAll = texture2D(shadowtex0, sampleCoord).r;
            float isBlockedByAnything = step(depthAll, shadowCoord.z - bias);

            if (isBlockedByAnything == 0.0) {
                shadowTotal += vec3(1.0);
                continue; 
            }

            float depthOpaque = texture2D(shadowtex1, sampleCoord).r;
            float isBlockedByOpaque = step(depthOpaque, shadowCoord.z - bias);

            if (isBlockedByOpaque == 1.0) {
                shadowTotal += vec3(0.0);
            } 
            else {
                vec4 tint = texture2D(shadowcolor0, sampleCoord);
                shadowTotal += tint.rgb;    
            }
        }
    }
    
    return shadowTotal / 9.0;
}

void main() {
    vec3 Color = texture2D(colortex0, texcoord).rgb;
    float depth = texture2D(depthtex0, texcoord).r;

    // --- DH Logic: Check if we hit vanilla terrain or DH terrain ---
    bool isDH = false;
    
    #ifdef DISTANT_HORIZONS
    // If vanilla depth is 1.0 (sky/void), check DH depth
    float depthDH = texture2D(dhDepthTex0, texcoord).r;
    if (depth >= 1.0 && depthDH < 1.0) {
        depth = depthDH;
        isDH = true;
    }
    #endif

    // Only process if we hit something (Vanilla OR DH)
    if (depth < 1.0) {
        // --- Coordinate Math ---
        vec4 clipPos = vec4(texcoord * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
        vec4 viewPos;
        
        // Use the correct projection inverse depending on what we hit
        #ifdef DISTANT_HORIZONS
        if (isDH) {
            viewPos = dhProjectionInverse * clipPos;
        } else {
            viewPos = gbufferProjectionInverse * clipPos;
        }
        #else
        viewPos = gbufferProjectionInverse * clipPos;
        #endif

        viewPos /= viewPos.w;
        vec4 worldPos = gbufferModelViewInverse * viewPos;

        vec4 shadowPos = shadowModelView * worldPos;
        shadowPos = shadowProjection * shadowPos;
        vec3 distortedPos = Distort(shadowPos.xyz);
        vec3 shadowCoords = distortedPos * 0.5 + 0.5;

        vec3 incomingLight = GetShadowColor(shadowCoords);

        // As night falls, force the shadow multiplier closer to 1.0
        incomingLight = mix(incomingLight, vec3(1.0), nightStrength * 0.8);

        // --- END NEW LOGIC ---

        const vec3 SUN_COLOR = vec3(1.6, 1.0, 0.6);
        float What = sunriseStrength + sunsetStrength;
    
        vec3 finalColor = SUN_COLOR * (dayStrength + What);
        
        // --- DYNAMIC AMBIENT LOGIC ---
        vec3 dayShadow = vec3(0.15, 0.15, 0.30); 
        vec3 nightLight = vec3(1.20, 1.20, 1.35); 

        float timeMix = clamp(dayStrength + sunriseStrength + sunsetStrength, 0.0, 1.0);
        vec3 ambientColor = mix(nightLight, dayShadow, timeMix); 

        float timeWeight = dayStrength + sunriseStrength + sunsetStrength;
        
        vec3 finalSunlight = finalColor * timeWeight * incomingLight;
        
        Color *= (ambientColor + finalSunlight);
        
        // --- Grading & Exposure ---
        float gray = dot(Color, vec3(0.299, 0.587, 0.114));
        Color = mix(vec3(gray), Color, 1.15); 
        
        Color *= 0.6; 
        Color *= vec3(1.05, 1.0, 0.95);
    }

    gl_FragColor = vec4(Color, 1.0);
}