#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) {

    float t = pow(Temperature, - 1.5);
    float lt = log(Temperature);

    vec3 col = vec3(0.0);
    col.x = 220000.0 * t + 0.58039215686;
    col.y = 0.39231372549 * lt - 2.44549019608;
    col.y = Temperature > 6500. ? 138039.215686 * t + 0.72156862745 : col.y;
    col.z = 0.76078431372 * lt - 5.68078431373;
    col = clamp01(col);
    col = Temperature < 1000. ? col * Temperature * 0.001 : col;

    return toLinear(col);
}

float CurveBlockLight(float blockLight){

    float decode=pow(blockLight, 1.0 / 0.25);
    #ifdef LIGHT_JITTER
        const float speed = JITTER_SPEED;
        float jitter1 = 1.0 - sin(frameTimeCounter * 1.4 * speed + cos(frameTimeCounter * 6.9 * speed) - sin(frameTimeCounter * 9.5 * speed)) * JITTER_STRENGTH1;
        float jitter2 = 1.0 - sin(frameTimeCounter * 1.4 * speed + cos(frameTimeCounter * 3.0 * speed) - sin(frameTimeCounter * 4.5 * speed)) * JITTER_STRENGTH2;
        float jitter3 = 1.0 - sin(frameTimeCounter * 1.4 * speed + cos(frameTimeCounter * 1.5 * speed) - sin(frameTimeCounter * 2.5 * speed)) * JITTER_STRENGTH3;
    #endif

    #ifdef LIGHT_JITTER
        decode*=jitter1 * jitter2 * jitter3;
    #endif

    return decode;
}

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

        #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

        #ifdef ENABLE_DARKNESS_EFFECT
            #if MC_VERSION >= 11900
                if (darknessFactor>0.001) shadow *= 0.25;
            #endif
        #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, 6.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);

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

        #ifdef 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 * 1.03, 1.0), 200.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

            #ifdef ENABLE_DARKNESS_EFFECT
                #if MC_VERSION >= 11900
                    if (darknessFactor > 0.001) sceneLighting *= 0.2;
                #endif
            #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);
            }
        #endif

        #ifdef 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 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)) / 25.0, 0.0, 0.9333);
    #else
        handLightFactor = clamp((handLight - 1.0 * length(viewPos)) / 15.0, 0.0, 0.9333);
    #endif

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

    if (isLightHandled()) {

        if (isEyeInWater == 1) {
            distMaxLight = DIST_MAX_LIGHT * 2.0;
            maxLight = MAX_LIGHT * 1.1;
        } else {
            distMaxLight = DIST_MAX_LIGHT;
            maxLight = MAX_LIGHT;
        }

        handTorchLightmap = clamp01(1.0 - ((torchDist - distMaxLight) / (DIST_DECLINE - distMaxLight))) * 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 < 2
        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 HAND
        #ifdef BLOCKLIGHT_BY_TEMP
            blocklightCol=BlackBody(BLOCKLIGHT_TEMP) * 2.0 * BLOCKLIGHT_LUMA;
        #endif
    #endif

    handTorchLightmap=CurveBlockLight(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

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

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

    float shade = pow(vanillaDiffuse, SHADING_STRENGTH);

    vec3 emissiveLighting = albedo.rgb * emission * 4.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 = vec3(0.5);
    albedo *= max(sceneLighting + blockLighting + emissiveLighting + nightVisionLighting + minLighting, vec3(0.0));
    albedo *= shade;
    albedo *= 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

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