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

#include "/lib/lighting/colorLighting.glsl"

vec3 toLinear(vec3 color) {

    return mix(color / 12.92, pow((color + 0.055) / 1.055, vec3(2.4)), vec3(greaterThan(color, vec3(0.04045))));
}

vec3 BlackBody(float temperature) {
    temperature /= 100.0;
    if (temperature < 66.0) {
        return vec3(
            1.0,
            clamp(0.3900815787690196 * log(temperature) - 0.6318414437886275, 0.0, 1.0),
            clamp(0.543206789110196 * log(temperature - 10.0) - 1.19625408914, 0.0, 1.0)
        );
    } else {
        return vec3(
            clamp(1.292936186062745 * pow(temperature - 60.0, -0.1332047592),0.0, 1.0),
            clamp(1.129890860895294 * pow(temperature - 60.0, -0.0755148492),0.0, 1.0),
            1.0
        );
    }
}

float CurveBlockLight(const in float blockLight){

    float bdecode = pow(blockLight, 4.0);
    #ifdef GBUFFERS_HAND
    if (isEyeInWater > 0.5) bdecode = pow(blockLight, 20.0);
    #endif
    #ifdef BLOCK_LIGHT_JITTER
        const float bspeed = JITTER_SPEED;
        float btime = frameTimeCounter * bspeed;
        float bjitter1 = 1.0 - sin(btime * 1.4 + cos(btime * 6.9) - sin(btime * 9.5)) * JITTER_STRENGTH1;
        float bjitter2 = 1.0 - sin(btime * 1.4 + cos(btime * 3.0) - sin(btime * 4.5)) * JITTER_STRENGTH2;
        float bjitter3 = 1.0 - sin(btime * 1.4 + cos(btime * 1.5) - sin(btime * 2.5)) * JITTER_STRENGTH3;
        bdecode *= bjitter1 * bjitter2 * bjitter3;
    #endif

    return bdecode;
}

float CurveBlockLightHand(const in float blockLighthand){

    float hdecode = pow(blockLighthand, 4.0);
    #ifdef GBUFFERS_HAND
    if (isEyeInWater > 0.5) hdecode = pow(blockLighthand, 20.0);
    #endif
    #ifdef HAND_BLOCK_LIGHT_JITTER
        const float hspeed = JITTER_SPEED;
        float htime = frameTimeCounter * hspeed;
        float hjitter1 = 1.0 - sin(htime * 1.3 + cos(htime * 6.7) - sin(htime * 9.4)) * JITTER_STRENGTH1;
        float hjitter2 = 1.0 - sin(htime * 1.3 + cos(htime * 2.8) - sin(htime * 4.4)) * JITTER_STRENGTH2;
        float hjitter3 = 1.0 - sin(htime * 1.3 + cos(htime * 1.3) - sin(htime * 2.4)) * JITTER_STRENGTH3;
        hdecode *= hjitter1 * hjitter2 * hjitter3;
    #endif

    return hdecode;
}

void GetLighting(inout vec3 albedo, out vec3 shadow, vec3 viewPos, vec3 worldPos, vec2 lightmap, float smoothLighting, float NoL, float vanillaDiffuse, float parallaxShadow, float emission, float subsurface, bool activateBlockLighting){

        #if ((!defined ADVANCED_MATERIALS && EMISSIVE == 1) || EMISSIVE == 0)
            emission = 0.0;
        #endif

        lightmap.x = Max0(lightmap.x * 1.15 - 0.15);
        lightmap.y = sqrt(lightmap.y);
        float shadowMult = 1.0;
        float shadowTime = 1.0;
        float moonPhaseOffsetShadows = 1.0;
        float handLightFactor = 0.0;
        float newLightMap = 0.0;
        float newLightmap = 0.0;

        vec3 shadowDecider = vec3(0.0);
        vec3 sceneLighting = vec3(0.0);
        vec3 blockLighting = vec3(0.0);

        #ifdef NEWMOON_DISABLER_STUFF
            moonPhaseOffsetShadows = 1.0 - (float((moonPhase == 4)) * (1.0 - sunVisibility));
        #endif

        #ifndef SSS
            subsurface = 0.0;
        #endif

    #if (defined OVERWORLD || defined END)
        if (NoL > 0.0 || subsurface > 0.0) {
            shadow = GetShadow(worldPos, NoL, subsurface, lightmap.y, color.a);
        }

        shadow *= parallaxShadow;
        shadow = max(shadow, vec3(0.0));
        NoL = clamp01(NoL * 1.01 - 0.01);

        #ifdef OVERWORLD
            #ifdef NEWMOON_DISABLER_STUFF
                shadow = mix(shadow, vec3(lightmap.y) * NEWMOON_SHADOWS_LIGHTMAP_CONTROL, (float(moonPhase == 4) * (1.0 - sunVisibility)));
            #else
                shadow *= moonPhaseOffsetShadows;
            #endif
        #endif

        #if defined ENABLE_DARKNESS_EFFECT && MC_VERSION >= 11900
            if (darknessFactor>0.001) shadow *= 0.25;
        #endif

        float scattering = 0.0;

        vec3 fullShadow = max(shadow * NoL, vec3(0.0));

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

            float VoL = clamp01(dot(normalize(viewPos.xyz), lightVec) * 0.5 + 0.5);

            scattering = pow(VoL, 16.0) * (1.0 - rainStrengthS);
            scattering = mix(SSS_NIGHT_STRENGTH, SSS_DAY_STRENGTH, sunVisibility);
            scattering *= shadowFade * moonPhaseOffsetShadows;

            vec3 subsurfaceColor = mix(albedo.rgb, vec3(4.0), scattering) * sqrt(subsurface);

            fullShadow = mix(subsurfaceColor * subsurfaceShadow, vec3(1.0), fullShadow);
        }

        #if defined (OVERWORLD)

            shadowMult = 1.0 * (1.0 - 0.95 * rainStrengthS) * shadowFade;
            shadowTime = abs(sunVisibility - 0.5) * 2.0;
            shadowTime *= shadowTime;
            shadowMult *= pow2(shadowTime);

            if (isEyeInWater == 1) ambientCol *= pow(lightmap.y, 2.5);

            vec3 lightingCol = pow(lightCol, vec3(1.0 + sunVisibility * 1.0 - timeBrightness));

            shadowDecider = fullShadow * shadowMult;
            if (isEyeInWater == 1) shadowDecider *= pow(min(lightmap.y * 0.75, 1.0), 10.0);

            sceneLighting = mix(mix(ambientCol * AMBIENT_MULT_NIGHT, lightingCol * LIGHT_MULT_NIGHT, shadowDecider),
                                mix(ambientCol * AMBIENT_GROUND_DAY, lightingCol * LIGHT_GROUND_DAY, shadowDecider),
                                    sunVisibility);

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

            #if defined ENABLE_DARKNESS_EFFECT && MC_VERSION >= 11900
                if (darknessFactor > 0.001) sceneLighting *= 0.2;
            #endif

            float newlightmapy = lightmap.y;

            vec3 fullShadowCausticsUderwater = max(shadow * NoL, vec3(0.0));

            if (isEyeInWater == 1 ){

                #if (defined WATER_CAUSTICS && defined LIGHT_SHAFT)
                if(length(fullShadowCausticsUderwater) > 0.01){
                    newlightmapy += 0.1;
                }
                #endif

            }else{
                sceneLighting *= pow(newlightmapy, 2.5);
            }

        #elif defined (END)
            float brightnessEnd = 0.0;

            #if BRIGHTNESS_END == 1
                brightnessEnd = AMBIANT_END;
            #elif BRIGHTNESS_END == 2
                brightnessEnd = AMBIANT_END * 100;
            #endif

            vec3 ambientEnd = endCol.rgb * 0.17 * brightnessEnd;
            vec3 lightEnd   = endCol.rgb * 0.37 * brightnessEnd;
            shadowDecider = fullShadow * 3.0;
            sceneLighting = mix(ambientEnd, lightEnd, shadowDecider);
            sceneLighting *= 0.20 * (0.7 + 0.3 * screenBrightness2);
        #endif

    #else
        sceneLighting = netherColSqrt.rgb * 0.07;
    #endif

    float distMaxLight = 0.0;
    float distDecline  = 0.0;
    float maxLight = 0.0;
    float torchDist=length(viewPos);
    float handTorchLightmap=0.0;
    vec3 handLightCol=vec3(0.1);

    float handLight = max(float(heldBlockLightValue), float(heldBlockLightValue2));


    #ifdef COLORED_DYNAMIC_HAND_LIGHT
        handLightFactor = clamp((handLight - 2.0 * length(viewPos)) / 18.0, 0.0, 0.9333);
    #else
        handLightFactor = clamp((handLight - 1.0 * length(viewPos)) / 15.0, 0.0, 0.9333);
    #endif
    #ifdef GBUFFERS_HAND
    handLightFactor = clamp((handLight - 1.0 * length(viewPos)) / 1.0, 0.0, 0.933);
    if (isEyeInWater > 0) handLightFactor = mix(clamp((handLight * length(viewPos)) / 2.0, 0.0, 0.955),
                                                clamp((handLight * length(viewPos)) / 2.0, 0.0, 0.9333), sunVisibility);
    #endif

    lightmap.x = max(lightmap.x, handLightFactor);

    #ifdef GBUFFERS_HAND
        distMaxLight = 1.0;
        distDecline = 1.0;
        maxLight = 0.7;
    #else
        distMaxLight = (isEyeInWater == 1) ? DIST_MAX_LIGHT * 2.0 : DIST_MAX_LIGHT;
        distDecline  = (isEyeInWater == 1) ? DIST_DECLINE * 2.0 : DIST_DECLINE;
        maxLight = MAX_LIGHT;
    #endif

    if (isLightHandled()) {
        handTorchLightmap = smoothClamp(1.0 - ((torchDist - distMaxLight) / (distDecline - distMaxLight)), 0.0, maxLight);

        #ifdef COLORED_DYNAMIC_HAND_LIGHT
            changeLightingColorByHand(handLightCol);
        #endif
    }

    float LightPower=mix(LIGHTING_POWER_NIGHT, LIGHTING_POWER_DAY, sunVisibility);

    if (isEyeInWater==0){
        LightPower = mix(LIGHTING_POWER_INSIDE, LightPower, eBS);
    }else if (isEyeInWater==1){
        LightPower = mix(LIGHTING_POWER_UNDERWATER, LightPower, eBS);
    }

    #if CONCENTRATE_BLOCK_LIGHT == 1
        newLightmap  = pow(lightmap.x, 120.0 / LightPower) * 0.5 + Max0((lightmap.x - 0.05) * 0.925) * (screenBrightness2 * 0.05 + 0.95);
    #else
        newLightmap  = sqrt(pow(lightmap.x, 120.0 / LightPower) * 0.5 + Max0((lightmap.x - 0.05) * 0.925) * (screenBrightness2 * 0.05 + 0.95));
    #endif

    #ifndef GBUFFERS_HAND
        #ifdef BLOCKLIGHT_BY_TEMP
        if(activateBlockLighting){
            blocklightCol=BlackBody(BLOCKLIGHT_TEMP) * BLOCKLIGHT_LUMA;
        }
        #endif
    #endif

    handTorchLightmap =CurveBlockLightHand(handTorchLightmap);

    newLightmap=CurveBlockLight(newLightmap);

    #ifdef OVERWORLD

        #if SHINE_BLOCKLIGHTINGLIMITER < 1
            newLightMap = newLightmap;
        #else
            newLightMap = newLightmap * newLightmap;
        #endif

        #ifdef COLORED_LIGHTING
            float CLr = textureLod(noisetex, 0.00009 * (worldPos.xz + cameraPosition.xz), 0).r;
            float CLg = textureLod(noisetex, 0.00012 * (worldPos.xz + cameraPosition.xz), 0).r;
            float CLb = textureLod(noisetex, 0.00018 * (worldPos.xz + cameraPosition.xz), 0).r;
            blocklightCol = vec3(CLr, CLg, CLb) * 2.2;
            blocklightCol *= blocklightCol;
            blocklightCol *= blocklightCol * 0.7;
            blocklightCol *= sqrt(blocklightCol);
        #endif

        blockLighting=max(blocklightCol * newLightMap, handLightCol * (handTorchLightmap));
    #else
        blockLighting=max(blocklightCol * newLightmap, handLightCol * (handTorchLightmap));
    #endif

    #ifdef GBUFFERS_HAND
        blockLighting=max(HandBlocklightCol * newLightmap, vec3(0.5) * (handTorchLightmap));
    #endif

    float lightFlatten = clamp01(1.0 - pow(1.0 - emission, 128.0));

    vanillaDiffuse = mix(vanillaDiffuse, 1.0, lightFlatten);
    smoothLighting = mix(smoothLighting, 1.0, lightFlatten);
    smoothLighting = clamp01(smoothLighting);

    float shade = pow(vanillaDiffuse, SHADING_STRENGTH);

    vec3 emissiveLighting = albedo.rgb * emission * 6.0 / shade * EMISSIVE_MULTIPLIER;

    float nightVisionLighting = nightVision * 0.25;

    vec3 minLighting = minLightCol * (1.0 - lightmap.y * lightmap.y);
         minLighting *= ((isEyeInWater == 1) ? MINLIGHT_U_I : MINLIGHT_I);

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

    #if (defined GBUFFERS_HAND && defined HAND_BLOOM_REDUCTION)
        float strenghtAlbedo = (albedo.r + albedo.g + albedo.b) / HAND_BLOOM_REDUCTION_STRENGTH;
        if (strenghtAlbedo > 1.0) albedo.rgb = albedo.rgb * max(2.0 - strenghtAlbedo, 0.34);
    #endif

    #if (defined ENABLE_DARKNESS_EFFECT && MC_VERSION >= 11900)
        albedo *= 1.0 - clamp(darknessLightFactor * (2.0 - emission * 10000.0), 0.0, 1.0);
    #endif
}