#version 330 core 
#define GLSL_VERSION 3.00
#define PI 3.14159265359

out vec4 FragColor;

in vec3 FragPos;
in vec3 ourNormal;
in vec2 TexCoord;
in float time;
in float height;

uniform mat4 invProjection;         // Inverse projection matrix
uniform mat4 invView;               // Inverse view matrix
//uniform sampler2D texture1;
uniform vec3 sunPos;
uniform vec3 moonPos;
uniform vec3 viewPos;
uniform float daytime; // 1-0-1 night-day-night

float linearizeDepth(float depth) {
    float near=0.1f;
    float far=5000.0f;

    float z = depth * 2.0 - 1.0; // NDC
    return 2.0 * near * far / (far + near - z * (far - near));
}
vec3 getWorldPosition(float depth, vec2 uv, bool linearize) {
    float z = linearize ? linearizeDepth(depth) : (depth * 2.0 - 1.0);
    vec4 clipSpace = vec4(uv * 2.0 - 1.0, linearize ? depth : z, 1.0);
    vec4 viewSpace = invProjection * clipSpace;
    viewSpace /= viewSpace.w;
    vec4 worldSpace = invView * viewSpace;
    return worldSpace.xyz;
}



// Sine-based noise function for wave generation
float sineFunction(vec2 uv) {
    // Adjusting the frequency based on distance from origin
    //float frequency = smoothstep(0.1, 1000.0) * 10.0;
    float frequency = smoothstep(0.1, 1000.0, 0.2);
    //float frequency = 1.0;

    float x = sin(uv.y * frequency) + sin(uv.x * frequency);
    return (x / 2.0) - 0.5;
}

// Simple 2D noise function
float noise3(vec2 p) {
    // A basic pseudo-random function (not true Perlin noise, but sufficient for perturbation)
    return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
    //return sin(dot(p, vec2(25, 125))) * 5;
}

// Simple fractal noise with wrapping behavior
vec3 fractalNoise(vec2 uv) {
    vec3 result;

    // Generate a smooth sine wave that wraps around horizontally
    float x = sin(uv.y * 2.0 + time) * 0.5; // Frequency (25 is a good starting point)
    x += sin(((uv.x * 0.5) * 5.0 + time) * 0.3); // Add a sub-wave for more detail
    
    // Create a smoother transition between waves
    x = x * 0.8 + 0.4; // Offset to prevent sharp peaks
    
    // Apply the noise pattern to UV coordinates
    result.x = x;
    result.y = uv.y;
    //result.z = (x > 0.5) ? sqrt(x - 0.5) : 0; // Create a dynamic depth effect that fades out
    result.z = x;
    
    return result;
}


void main() {
    vec3 resultColor = vec3(1.0, 1.0, 1.0);

    float uvscale = 1.0;
    
    // Calculate UV coordinates based on position
    vec2 uv = TexCoord.xy * uvscale; // max w/h view
    vec3 basePlaneTexture = vec3(0.0,0.2,0.5);
    vec3 waveTexture = vec3(0.0, 0.3, 0.8);
    //vec3 finalPassTexture = vec3(1.0,0.0,0.0);

    
    // Combine base plane with vertex-generated waves and ripples
    resultColor = mix(basePlaneTexture, waveTexture, sin(uv.x)-sin(uv.y));
    
	vec3 noise = fractalNoise(uv);
	
	// Apply the noise to create a dynamic, looping pattern
    float timeMultiplier = 0.2 + sin(time * .5); // Create a slow animation of the noise pattern
    
    vec3 finalColor = vec3(
        0.0,
        (noise.z * 0.3) * (timeMultiplier),
        (noise.x * 0.7) * timeMultiplier
    );
    //resultColor += noise * 0.5;
    resultColor += finalColor;

    float ambientStrength = 0.4f;
    vec3 sunColor = vec3(1.0f, 0.93f, 0.74f); // luminate color
    vec3 moonColor = vec3(0.38f, 0.5f, 0.5f); // _sky and _moon
    //vec3 objColor = vec3(0.2f, 0.9f, 0.1f); // for sphere color
    //vec3 norm=normalize(ourNormal);
    vec3 norm=ourNormal*.01;

    float sunY=sunPos.y*0.01; // 1000th = normalized?~
    float sunStrength=clamp(sunY,0.0,1.3); // sun brightness
    float moonStrength=clamp(1.0-sunStrength,0.0,0.5);
    vec3 blendColor = mix(sunColor,moonColor,0.0-sunStrength); // tone?
    vec3 ambient = ambientStrength * blendColor;


    vec3 sunDir=normalize(sunPos - FragPos);
    float diff=max(dot(norm, sunDir), 0.0);
    vec3 diffuse=diff*sunColor*sunStrength;

    vec3 moonDir=normalize(moonPos - FragPos);
    float diff2=max(dot(norm, moonDir), 0.0);
    vec3 diffuse2=diff2*moonColor*moonStrength;


    // specular
    float specularStrength = 1.0;
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(sunDir, norm); // lightDir
    vec3 reflectDir2 = reflect(moonDir, norm); // lightDir
    //vec3 halfwayDir = normalize(sunDir + viewDir); // lightDir
    //vec3 halfwayDir2 = normalize(moonDir + viewDir); // lightDir

    float spec=pow(max(dot(viewDir, reflectDir), 0.0), 32);
    float spec2=pow(max(dot(viewDir, reflectDir2), 0.0), 32);
    //float spec=pow(max(dot(ourNormal, halfwayDir), 0.0), 128);
    //float spec2=pow(max(dot(ourNormal, halfwayDir2), 0.0), 128);
    vec3 specular = specularStrength * spec * sunColor;
    vec3 specular2 = specularStrength * spec2 * moonColor;




    //vec3 tFog = fogColor;
    // Initialize output color
    //vec3 P = getWorldPosition(FragPos.z, TexCoord, false);
    vec3 P = getWorldPosition((FragPos.z+2), TexCoord, false); // +1 adds dark near view , +1 or +2, 0 makes a line across screen


    float distance = length(P - viewPos);
    float fogDistance = 50.0f;
    float fogHeight = 25.0;
    float tFac = clamp(normalize(viewPos.y)/fogHeight,1.2,1.8); // min max fac
    float fogFac = clamp(distance / fogDistance, 0.0, 0.5*tFac);

    float dt=abs(daytime);

    float methodA=dt;
    float methodD=(methodA*2);
    float methodE=(methodA*2)-1;

    // day/night water fog colors  blend
    vec3 color1 = vec3(0.0,0.3,0.32); // day
    vec3 color2 = vec3(0.1,0.36,0.46);
    vec3 color3 = vec3(0.1,0.4,0.46); // <<day begin
    //
    vec3 color4 = vec3(0.02,0.02,0.06); // night
    vec3 color5 = vec3(0.02,0.03,0.05);
    vec3 color6 = vec3(0.01,0.05,0.07);
 
    vec3 ourColor = vec3(mix(color3,color2,methodD));
    ourColor = mix(ourColor,color1,methodE);
    vec3 ourColor2 = vec3(mix(color5,color4,methodD));
    ourColor2 = mix(ourColor2,color6,methodE);
    vec3 fogColor = vec3(mix(ourColor,ourColor2,dt));



    float waterSurfaceFac = 0.0f;
    float terrainSurfaceFac = 0.0;





    //resultColor=(ambient + (max(diffuse,diffuse2)) + (max(specular,specular2))) * resultColor;
    resultColor=(ambient + ((diffuse + diffuse2) * 0.5) + ((specular + specular2) * 2.0)) * resultColor;
    resultColor *= .8;
    resultColor += 0.2;
    
    //resultColor = mix(fogColor, resultColor, 1.0-clamp((terrainSurfaceFac * .4 +(distance*.01)),0.0,1.0));
    resultColor = mix(fogColor, resultColor, clamp((terrainSurfaceFac * .4 +(distance*.1)),0.2,1.0));


    //resultColor=vec3(distance,0.0,0.0);

    float alpha = clamp((1.0-distance*.1)*.3,0.0,1.0);
    FragColor = vec4(resultColor, 0.7+alpha);
}
