#if defined OVERWORLD || defined END
#include "/lib/lighting/shadows.glsl"
#endif

void GetLighting(inout vec3 albedo, out vec3 shadow, vec3 viewPos, vec3 worldPos, vec3 normal, 
                 vec2 lightmap, float smoothLighting, float NoL, float vanillaDiffuse,
                 float parallaxShadow, float emission, float subsurface, float basicSubsurface) {
    #if EMISSIVE == 0 || (!defined ADVANCED_MATERIALS && EMISSIVE == 1)
    emission = 0.0;
    #endif

    #ifndef SSS
    subsurface = 0.0;
    #endif
    
    #ifndef BASIC_SSS
    basicSubsurface = 0.0;
    #endif

    // Verlixia: cubic falloff — sky light 1/15 in caves drops to ~0 instead of barely-visible
    float skylightSqr = lightmap.y * lightmap.y * lightmap.y;

    #if defined OVERWORLD || defined END
    #ifdef SHADOW
    if (NoL > 0.0 || basicSubsurface > 0.0) {
        shadow = GetShadow(worldPos, normal, NoL, basicSubsurface, lightmap.y);
    }
    shadow *= parallaxShadow;
    shadow = max(shadow, vec3(0.0));
    NoL = clamp(NoL * 1.01 - 0.01, 0.0, 1.0);
    #else
    shadow = GetShadow(worldPos, normal, NoL, basicSubsurface, lightmap.y);
    #endif

    #ifdef SHADOW_CLOUD
    float cloudShadow = GetCloudShadow(worldPos);
    shadow *= cloudShadow;
    #endif
    
    float scattering = 0.0;
    vec3 foliageSSSTint = vec3(1.0);
    if (basicSubsurface > 0.0){
        float VoL = clamp(dot(normalize(viewPos.xyz), lightVec) * 0.5 + 0.5, 0.0, 1.0);
        float VoLp = VoL * VoL; VoLp = VoLp * VoLp; VoLp = VoLp * VoLp; VoLp = VoLp * VoLp; // pow(VoL,16) via squaring
        scattering = VoLp * (1.0 - rainStrength) * basicSubsurface * shadowFade;
        NoL = mix(NoL, 1.0, sqrt(basicSubsurface) * 0.7);
        NoL = mix(NoL, 1.0, scattering);

        // Verlixia: jade/emerald glow on backlit foliage
        vec3 jadeGlow = vec3(0.45, 1.0, 0.55);
        foliageSSSTint = mix(vec3(1.0), jadeGlow, scattering * 0.6);
    }
    
    #ifdef SHADOW
    vec3 fullShadow = max(shadow * NoL, vec3(0.0));
    #else
    vec3 fullShadow = vec3(shadow);
    #ifdef OVERWORLD
    float timeBrightnessAbs = abs(sin(timeAngle * 6.28318530718));
    fullShadow *= 0.25 + 0.5 * (1.0 - (1.0 - timeBrightnessAbs) * (1.0 - timeBrightnessAbs));
    fullShadow *= mix(pow(vanillaDiffuse, 1.0 + timeBrightnessAbs), 1.0, basicSubsurface * 0.4);
    #else
    fullShadow *= 0.75;
    #endif
    #endif

    #ifdef ADVANCED_MATERIALS
    if (subsurface > 0.0){
        vec3 subsurfaceShadow = GetSubsurfaceShadow(worldPos, subsurface, lightmap.y);

        float VoL = clamp(dot(normalize(viewPos.xyz), lightVec) * 0.5 + 0.5, 0.0, 1.0);
        float volP = VoL * VoL; volP = volP * volP; volP = volP * volP; volP = volP * volP; // pow(VoL,16)
        float scattering = volP * (1.0 - rainStrength) * shadowFade;

        vec3 subsurfaceColor = normalize(albedo + 0.00001) * 1.2;
        vec3 ss2 = subsurfaceShadow * subsurfaceShadow;
        subsurfaceColor = mix(subsurfaceColor, vec3(1.0), ss2 * ss2);
        subsurfaceColor = mix(subsurfaceColor, vec3(4.0), scattering) * sqrt(subsurface);

        fullShadow = mix(subsurfaceColor * subsurfaceShadow, vec3(1.0), fullShadow);
    }
    #endif
    
    #ifdef OVERWORLD
    float shadowMult = (1.0 - 0.95 * rainStrength) * shadowFade;
    // Verlixia: sky-blue ambient fill in outdoor shadows
    vec3 skyAmbient = ambientCol * lightmap.y * vec3(0.85, 0.93, 1.18);
    vec3 sceneLighting = mix(skyAmbient, lightCol, fullShadow * shadowMult);

    // Verlixia: dramatic indigo/purple shadow tinting
    float shadowDepth = 1.0 - clamp(dot(fullShadow, vec3(0.333)) * shadowMult, 0.0, 1.0);
    vec3 indigoTint = vec3(0.28, 0.22, 0.48); // deep indigo-purple
    sceneLighting = mix(sceneLighting, sceneLighting * indigoTint * 2.8, shadowDepth * shadowDepth * 0.35);

    sceneLighting *= skylightSqr * (1.0 + scattering * shadow) * foliageSSSTint;

    #ifdef CLASSIC_EXPOSURE
    sceneLighting *= 4.0 - 3.0 * eBS;
    #endif
    #endif

    #ifdef END
    vec3 sceneLighting = endCol.rgb * (0.04 * fullShadow + 0.015);
    #endif

    #else
    vec3 sceneLighting = netherColSqrt.rgb * 0.07;
    #endif
    
    // Verlixia: smoother blocklight falloff with warmer close-range tint
    float lx2 = lightmap.x * lightmap.x;
    float lx4 = lx2 * lx2;
    float newLightmap  = lx4 * lx4 * lx2 * 1.5 + lightmap.x * 0.65; // pow(x,10) via squaring
    vec3 blockLighting = blocklightCol * newLightmap * newLightmap;
    blockLighting *= 1.0 + vec3(0.04, 0.01, -0.03) * lightmap.x;

    vec3 minLighting = minLightCol * (1.0 - skylightSqr);

    #ifdef TOON_LIGHTMAP
    minLighting *= floor(smoothLighting * 8.0 + 1.001) / 4.0;
    smoothLighting = 1.0;
    #endif
    
    vec3 albedoNormalized = normalize(albedo.rgb + 0.00001);
    vec3 emissiveLighting = mix(albedoNormalized, vec3(1.0), emission * 0.5);
    emissiveLighting *= emission * 4.0;

    float ie = 1.0 - emission; ie*=ie; ie*=ie; ie*=ie; ie*=ie; ie*=ie; ie*=ie; ie*=ie; // pow(1-emission,128)
    float lightFlatten = clamp(1.0 - ie, 0.0, 1.0);
    vanillaDiffuse = mix(vanillaDiffuse, 1.0, lightFlatten);
    smoothLighting = mix(smoothLighting, 1.0, lightFlatten);
        
    float nightVisionLighting = nightVision * 0.25;
    
    #ifdef ALBEDO_BALANCING
    float albedoLength = length(albedo.rgb);
    albedoLength /= sqrt((albedoLength * albedoLength) * 0.25 * (1.0 - lightFlatten) + 1.0);
    albedo.rgb = albedoNormalized * albedoLength;
    #endif

    //albedo = vec3(0.5);
    albedo *= max(sceneLighting + blockLighting + emissiveLighting + nightVisionLighting + minLighting, vec3(0.0));
    albedo *= vanillaDiffuse * smoothLighting * smoothLighting;

    #ifdef DESATURATION
    #ifdef OVERWORLD
    // Verlixia: simplified desaturation math — fewer sqrt/length calls
    float shadowLum   = dot(fullShadow, vec3(0.333));
    float desatBase   = sqrt(max(sqrt(shadowLum) * lightmap.y, lightmap.y));
    float noLightMask = (1.0 - lightmap.x);
    float desatAmount = desatBase * sunVisibility * (1.0 - rainStrength * 0.7);
    desatAmount = 1.0 - (1.0 - desatAmount) * smoothstep(0.25, 1.0, noLightMask * noLightMask) * (1.0 - lightFlatten);

    vec3 desatNight   = normalize(lightNight * lightNight + 0.000001);
    vec3 desatWeather = normalize(weatherCol.rgb * weatherCol.rgb + 0.000001);
    
    float desatNWMix  = (1.0 - sunVisibility) * (1.0 - rainStrength);

    vec3 desatColor = mix(desatWeather, desatNight, desatNWMix);
    desatColor = mix(vec3(0.4), desatColor, sqrt(lightmap.y)) * 1.7;
    #endif

    #ifdef NETHER
    float noLightMask = (1.0 - lightmap.x);
    float desatAmount = 1.0 - smoothstep(0.25, 1.0, noLightMask * noLightMask) * (1.0 - lightFlatten);

    vec3 desatColor = normalize(netherColSqrt.rgb + 0.000001) * 1.7;
    #endif

    #ifdef END
    float noLightMask = (1.0 - lightmap.x);
    float desatAmount = 1.0 - smoothstep(0.25, 1.0, noLightMask * noLightMask) * (1.0 - lightFlatten);

    vec3 desatColor = normalize(endCol.rgb + 0.000001) * 1.7;
    #endif

    vec3 desatAlbedo = mix(albedo, GetLuminance(albedo) * desatColor, 1.0 - DESATURATION_FACTOR * 0.4);
    
    albedo = mix(desatAlbedo, albedo, desatAmount);
    #endif
}