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

#include "/settings/color/handlightColorSettings.glsl"
#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 concentrateLight = LIGHT_POWER;

    float bdecode = pow(blockLight, concentrateLight);
    #ifdef GBUFFERS_HAND
    bdecode = pow(blockLight, 0.25);
    #endif
    #ifdef BLOCK_LIGHT_JITTER
    const float bspeed = JITTER_SPEED * 0.5;
    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
    hdecode = pow(blockLighthand, 0.25);
    #endif
    #ifdef HAND_BLOCK_LIGHT_JITTER
    const float hspeed = JITTER_SPEED * 0.5;
    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, bool activateHandLight){

        #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);
            }

            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

        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);

            float scattering = pow(VoL, 16) * (1.0 - rainStrengthS) * shadowFade * moonPhaseOffsetShadows;

            vec3 subsurfaceColor = normalize(albedo + 0.00001) * 1.2;
            subsurfaceColor = mix(subsurfaceColor, vec3(2.0), pow(subsurfaceShadow, vec3(2.0)));
            subsurfaceColor = mix(subsurfaceColor, vec3(4.0), scattering) * sqrt(subsurface);
            subsurfaceColor *= mix(SSS_NIGHT_STRENGTH, SSS_DAY_STRENGTH, sunVisibility);

            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 *= shadowTime * shadowTime;

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

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

            shadowDecider = fullShadow * shadowMult;

            if (isEyeInWater == 1) shadowDecider *= pow(min(lightmap.y * 0.80, 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;
            sceneLighting = mix(ambientEnd, lightEnd, shadowDecider);
            sceneLighting *= 0.20 * (0.7 + 0.4 * 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);

    #if !defined DYNAMIC_HAND_LIGHT && defined BLOCKLIGHT_BY_TEMP
    handLightCol = BlackBody(BLOCKLIGHT_TEMP) * BLOCKLIGHT_LUMA;
    #endif

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

    if (activateHandLight){
    handLightFactor = clamp((handLight - 2.0 * length(viewPos)) / 18.0, 0.0, 0.9333);
    }else{
    handLightFactor = clamp((handLight - 2.0 * length(viewPos)) / 30.0, 0.0, 0.9333);
    }

    #if defined GBUFFERS_HAND
        handLightFactor = clamp(handLight / 18.0, 0.0, 0.9333);
        if (isEyeInWater > 0)handLightFactor = mix(clamp(handLight / 18.0, 0.0, 0.955), clamp(handLight / 18.0, 0.0, 0.9333), sunVisibility);
    #endif

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

    #ifdef GBUFFERS_HAND
        distMaxLight = 1.0;
        distDecline = 1.0;
        maxLight = 0.8;
    #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

    #ifndef DYNAMIC_HAND_LIGHT
        distMaxLight = (isEyeInWater == 1) ? 8.0 : 8.0;
        distDecline  = (isEyeInWater == 1) ? 16 : 16;
        maxLight = 0.0;
    #endif

    if (isLightHandled()) {

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

        #ifdef COLORED_DYNAMIC_HAND_LIGHT
            changeLightingColorByHand(handLightCol);
        #endif
    }

    float lightmapX2 = lightmap.x * lightmap.x;
	float lightmapXM1 = pow2(pow2(lightmapX2)) * lightmapX2;
	float lightmapXM2 = max((lightmap.x) * 0.925, 0.0);

	newLightmap = mix(lightmapXM1 * 5.0 + lightmapXM2, lightmapXM1 * 4.0 + lightmapXM2 * LIGHT_CONCENTRATION, screenBrightness2);

    #ifdef GBUFFERS_TEXTURED
    newLightmap = mix(lightmapXM1 * 0.2 + lightmapXM2, lightmapXM1 * 0.25 + lightmapXM2 , screenBrightness2);
    #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

        #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.1;
            blocklightCol *= sqrt(blocklightCol);
        #endif

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

    #ifdef GBUFFERS_HAND
        blockLighting=max(HandBlocklightCol * clamp01(pow16(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;
    if (isEyeInWater >= 1) emissiveLighting = clamp01(emissiveLighting);

    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
}