#include "commonSettings.glsl"
#include "lib.glsl"

// ============================================================
//  PaintBound Sky — gbuffers_skybasic.fsh
// ============================================================

uniform float viewHeight;
uniform float viewWidth;
uniform mat4  gbufferModelView;
uniform mat4  gbufferProjectionInverse;
uniform vec3  fogColor;               // vanilla fallback
uniform vec3  skyColor;               // vanilla fallback
uniform float sunAngle;               // 0=sunrise 0.25=noon 0.5=sunset 0.75=midnight
uniform vec3  shadowLightPosition;    // active light (sun or moon) in view-space
uniform mat4  gbufferModelViewInverse;
uniform sampler2D noisetex;
uniform float rainStrength;
uniform int   isEyeInWater;           // 1 = camera is submerged
uniform float nightVision;


varying vec4 starData; // rgb=star color, a=isStar flag


// ============================================================
//  SKY COLOR SETTINGS
// ============================================================

// --- Day ---
#define SKY_DAY_ZENITH_R  0.18 // Day Zenith Red   [0.00 0.02 0.04 0.06 0.08 0.10 0.12 0.14 0.16 0.18 0.20 0.22 0.24 0.26 0.28 0.30 0.35 0.40 0.45 0.50]
#define SKY_DAY_ZENITH_G  0.35 // Day Zenith Green [0.00 0.05 0.10 0.15 0.20 0.25 0.30 0.35 0.38 0.40 0.45 0.50 0.55 0.60 0.65 0.70]
#define SKY_DAY_ZENITH_B  0.75 // Day Zenith Blue  [0.00 0.10 0.20 0.30 0.40 0.50 0.55 0.60 0.65 0.70 0.75 0.80 0.85 0.90 0.95 1.00]

// Day/Night horizon colors are shared via commonSettings.glsl (SKY_DAY_HORIZON_*, SKY_NIGHT_HORIZON_*)
// Sunset/twilight tint colors are shared via commonSettings.glsl (SKY_SUNSET_*, SKY_TWILIGHT_*)

// --- Night ---
#define SKY_NIGHT_ZENITH_R  0.005 // Night Zenith Red   [0.000 0.002 0.004 0.005 0.006 0.008 0.010 0.015 0.020 0.030 0.040 0.050]
#define SKY_NIGHT_ZENITH_G  0.007 // Night Zenith Green [0.000 0.002 0.004 0.005 0.006 0.007 0.008 0.010 0.015 0.020 0.030 0.040 0.050]
#define SKY_NIGHT_ZENITH_B  0.030 // Night Zenith Blue  [0.000 0.005 0.010 0.015 0.020 0.025 0.030 0.035 0.040 0.050 0.060 0.080 0.100]
#define STARS_ENABLED 1 // [0 1] Show vanilla stars
#define STAR_BRIGHTNESS 0.75 // [0.0 0.25 0.5 0.75 1.0 1.5 2.0	]

// --- Horizon gradient shape ---
#define SKY_HORIZON_POWER 1.0 // Horizon Gradient Power [0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 5.0 6.0 8.0]

// --- Celestial halos ---
#define SKY_SUN_GLOW_R        1.00 // Sun Halo Red    [0.50 0.60 0.70 0.80 0.90 0.95 1.00]
#define SKY_SUN_GLOW_G        0.90 // Sun Halo Green  [0.40 0.50 0.60 0.70 0.80 0.85 0.90 0.95 1.00]
#define SKY_SUN_GLOW_B        0.60 // Sun Halo Blue   [0.00 0.10 0.20 0.30 0.40 0.50 0.60 0.70 0.80]
#define SKY_SUN_GLOW_SIZE     0.12 // Sun Halo Falloff [0.02 0.04 0.06 0.08 0.10 0.12 0.15 0.20 0.25 0.30]
#define SKY_SUN_GLOW_STRENGTH 0.60 // Sun Halo Strength [0.00 0.10 0.20 0.30 0.40 0.50 0.60 0.70 0.80 0.90 1.00]

#define SKY_MOON_GLOW_R        0.40 // Moon Halo Red   [0.00 0.10 0.20 0.30 0.40 0.50 0.60 0.70 0.80]
#define SKY_MOON_GLOW_G        0.50 // Moon Halo Green [0.10 0.20 0.30 0.40 0.50 0.60 0.70 0.80 0.90]
#define SKY_MOON_GLOW_B        0.80 // Moon Halo Blue  [0.30 0.40 0.50 0.60 0.70 0.75 0.80 0.85 0.90 0.95 1.00]
#define SKY_MOON_GLOW_SIZE     0.15 // Moon Halo Falloff [0.02 0.04 0.06 0.08 0.10 0.12 0.15 0.20 0.25 0.30]
#define SKY_MOON_GLOW_STRENGTH 0.00 // Moon Halo Strength [0.00 0.10 0.20 0.30 0.40 0.50 0.60 0.70 0.80 0.90 1.00]

// ============================================================
//  VANILLA FALLBACK
// ============================================================

float fogify(float x, float w) {
    return w / (x * x + w);
}

vec3 calcVanillaSkyColor(vec3 dir) {
    float upDot = dot(dir, gbufferModelView[1].xyz);
    return mix(skyColor, fogColor, fogify(max(upDot, 0.0), 0.25));
}

// ============================================================
//  TIME HELPERS  (sunAngle: 0=sunrise, 0.25=noon, 0.5=sunset, 0.75=midnight)
// ============================================================

float skyDayFactor() {
    float day  = smoothstep(0.50, 0.44, sunAngle);
    float rise = smoothstep(0.97, 1.00, sunAngle);
    float morn = 1.0 - smoothstep(0.00, 0.05, sunAngle);
    return clamp(day + rise + morn, 0.0, 1.0);
}

float sunriseWeight() {
    return clamp(
        smoothstep(0.96, 1.00, sunAngle) + (1.0 - smoothstep(0.00, 0.06, sunAngle)),
        0.0, 1.0
    );
}

float sunsetWeight() {
    return smoothstep(0.44, 0.50, sunAngle) * (1.0 - smoothstep(0.50, 0.56, sunAngle));
}

float transitionWeight() {
    return clamp(sunriseWeight() + sunsetWeight(), 0.0, 1.0);
}

float twilightWeight() {
    float afterSunset   = smoothstep(0.50, 0.54, sunAngle) * (1.0 - smoothstep(0.54, 0.60, sunAngle));
    float beforeSunrise = smoothstep(0.88, 0.93, sunAngle) * (1.0 - smoothstep(0.97, 1.00, sunAngle));
    return clamp(afterSunset + beforeSunrise, 0.0, 1.0);
}

float nightWeight() {
    return clamp(smoothstep(0.58, 0.65, sunAngle) - smoothstep(0.88, 0.95, sunAngle), 0.0, 1.0);
}

bool isSunActive() { return sunAngle < 0.5; }

// ============================================================
//  CUSTOM SKY
// ============================================================

vec3 calcCustomSkyColor(vec3 dir) {
    vec3  upDir       = gbufferModelView[1].xyz;
    float upDot       = dot(dir, upDir);
    float heightAbove = pow(max(upDot, 0.0), SKY_HORIZON_POWER); // 0=horizon, 1=zenith

    // --- Base day/night gradient ---
    vec3 dayColor = mix(
        vec3(SKY_DAY_HORIZON_R,   SKY_DAY_HORIZON_G,   SKY_DAY_HORIZON_B),
        vec3(SKY_DAY_ZENITH_R,    SKY_DAY_ZENITH_G,    SKY_DAY_ZENITH_B),
        heightAbove
    );
    vec3 nightColor = mix(
        vec3(SKY_NIGHT_HORIZON_R, SKY_NIGHT_HORIZON_G, SKY_NIGHT_HORIZON_B),
        vec3(SKY_NIGHT_ZENITH_R,  SKY_NIGHT_ZENITH_G,  SKY_NIGHT_ZENITH_B),
        heightAbove
    );
    vec3 baseColor = mix(nightColor, dayColor, skyDayFactor());

    // --- sun direction ---
    float sunAngleClamped = clamp(sunAngle < 0.5 ? sunAngle : 1.0 - sunAngle, 0.001, 0.499);
    vec3 worldSunDir = vec3( cos(sunAngleClamped * 2.0 * 3.14159265),  // +1 east(sunrise), -1 west(sunset)
                              sin(sunAngleClamped * 2.0 * 3.14159265),  // 0 at horizon, +1 at noon
                              0.0);
    vec3 dirWorld = normalize((gbufferModelViewInverse * vec4(dir, 0.0)).xyz);
    float sunDot  = dot(dirWorld, worldSunDir); // 1=toward sun, -1=away


    // --- Sky sunset/sunrise tint ---
    vec3  sunsetTint     = vec3(SKY_SUNSET_R, SKY_SUNSET_G, SKY_SUNSET_B);
    float tintHeightFade = mix(1.0, 0.4, heightAbove); // horizon 100% → zenith 40%
    float tintDirBias    = sunDot * 0.35 + 0.65; // 0.30 away from sun, 1.0 toward sun
    float tintAmt        = transitionWeight() * SKY_SUNSET_TINT_STRENGTH * tintHeightFade * tintDirBias;
    baseColor = mix(baseColor, sunsetTint, clamp(tintAmt, 0.0, 1.0));

    // --- Directional hot spot toward the sun ---
    // Guard 1 (geometric):  sunDot < 0 for any pixel on the moon's side → max(sunDot,0)=0 → hotspot=0
    float hotspot = pow(max(sunDot, 0.0), 1.0 / max(SKY_SUNSET_HOTSPOT_WIDTH, 0.001));
    hotspot *= clamp(1.0 - upDot * 2.5, 0.0, 1.0); // suppress above horizon line
    baseColor += sunsetTint * hotspot * transitionWeight() * SKY_SUNSET_HOTSPOT_STRENGTH;

    // --- Twilight tint ---
    float twilightFade  = mix(1.0, 0.5, heightAbove);
    float twF           = twilightWeight() * SKY_TWILIGHT_STRENGTH;
    vec3  twilightColor = vec3(SKY_TWILIGHT_R, SKY_TWILIGHT_G, SKY_TWILIGHT_B);
    baseColor = mix(baseColor, twilightColor * twilightFade, twF);

    // --- Celestial halos (fake atmospheric scattering) ---
    vec3 moonWorldDir = normalize((gbufferModelViewInverse * vec4(shadowLightPosition, 0.0)).xyz);
    float oneMinus  = max(1.0 - sunDot,                    0.0);
    float oneMinus2 = max(1.0 - dot(dirWorld, moonWorldDir), 0.0);

    float sunGlow = SKY_SUN_GLOW_STRENGTH / (1.0 + oneMinus / max(SKY_SUN_GLOW_SIZE, 0.001));
    sunGlow = clamp(sunGlow * 0.08, 0.0, 1.0);
    vec3 sunGlowContrib  = vec3(SKY_SUN_GLOW_R, SKY_SUN_GLOW_G, SKY_SUN_GLOW_B) * sunGlow * skyDayFactor();
    baseColor += sunGlowContrib;

    float moonGlow = SKY_MOON_GLOW_STRENGTH / (1.0 + oneMinus2 / max(SKY_MOON_GLOW_SIZE, 0.001));
    moonGlow = clamp(moonGlow * 0.06, 0.0, 1.0);
    vec3 moonGlowContrib = vec3(SKY_MOON_GLOW_R, SKY_MOON_GLOW_G, SKY_MOON_GLOW_B) * moonGlow * nightWeight();
    baseColor += moonGlowContrib;

    vec2 noiseUV = gl_FragCoord.xy / float(noiseTextureResolution);
    float bn = texture2D(noisetex, noiseUV).r;
    baseColor += vec3((bn - 0.5) / 255.0);

    // Rain darkening and desaturation.
    float skyLuma = dot(baseColor, vec3(0.299, 0.587, 0.114));
    baseColor = mix(baseColor, vec3(skyLuma), rainStrength * RAIN_SKY_DESATURATE);
    baseColor *= 1.0 - rainStrength * RAIN_SKY_DARKEN;

    // Rain scatter glow: a wide, soft bloom where the sun/moon is.
    if (rainStrength > 0.0) {
        float scatter  = 1.0 / (1.0 + oneMinus2 * 10.0);
        scatter = clamp(scatter * scatter, 0.0, 1.0);

        vec3 sunRainGlow  = vec3(0.85, 0.80, 0.70) * scatter * skyDayFactor();
        vec3 moonRainGlow = vec3(0.55, 0.60, 0.75) * scatter * nightWeight();

        baseColor += (sunRainGlow + moonRainGlow) * rainStrength * 0.17;
    }

    return clamp(baseColor, 0.0, 1.0);
}

// ============================================================
//  ENTRY POINT
// ============================================================

void main() {
    vec3 color;

    if (starData.a > 0.5) {
        #if STARS_ENABLED == 1
			color = starData.rgb * STAR_BRIGHTNESS;
		#else
			discard;
		#endif
    } else {
        vec4 pos = vec4(
            gl_FragCoord.xy / vec2(viewWidth, viewHeight) * 2.0 - 1.0,
            1.0, 1.0
        );
        pos = gbufferProjectionInverse * pos;
        vec3 dir = normalize(pos.xyz);

        #if WHITEOUT_SKY == 1
            color = vec3(0.78);
        #elif CUSTOM_SKY == 1 && defined(OVERWORLD)
            color = (isEyeInWater == 1) ? calcVanillaSkyColor(dir) : calcCustomSkyColor(dir);
        #else
            color = calcVanillaSkyColor(dir);
        #endif
    }

    if (nightVision > 0.0) {
        #define NV_BRIGHTNESS_LIFT    0.85  // How much dark sky is pushed toward bright grey
        #define NV_BRIGHTNESS_FLOOR   0.7   // Minimum brightness target for dark areas
        #define NV_CONTRAST_BOOST     0.15  // How much contrast is added
        #define NV_TINT_STRENGTH      0.5   // How strong the blue-green tint is 
        #define NV_TINT_R             0.55  // Tint red channel
        #define NV_TINT_G             0.75  // Tint green channel
        #define NV_TINT_B             0.60  // Tint blue channel
        #define NV_TINT_BRIGHTNESS    1.4   // Overall brightness of the tint color
        #define NV_DARK_CUTOFF        0.5   // Sky luma above this = no effect (raise to affect brighter skies too)

        float luma = dot(color, vec3(0.299, 0.587, 0.114));
        float darknessFactor = 1.0 - smoothstep(0.0, NV_DARK_CUTOFF, luma);
        float strength = nightVision * darknessFactor;

        // Brightness lift
        vec3 nvTarget = vec3(max(luma, NV_BRIGHTNESS_FLOOR));
        color = mix(color, nvTarget, strength * NV_BRIGHTNESS_LIFT);

        // Contrast boost + tint
        float nvLuma = dot(color, vec3(0.299, 0.587, 0.114));
        color = mix(vec3(nvLuma), color, 1.0 + NV_CONTRAST_BOOST * strength);
        color = mix(color, color * vec3(NV_TINT_R, NV_TINT_G, NV_TINT_B) * NV_TINT_BRIGHTNESS, strength * NV_TINT_STRENGTH);
        color = clamp(color, 0.0, 1.0);
    }

/* DRAWBUFFERS:0 */
    gl_FragData[0] = vec4(color, 1.0);
}
