#version 330 core
out vec4 FragColor;

in vec3 FragCoord;
in vec3 ourColor;
in vec2 TexCoord;

uniform sampler2DMS screenTexture; // color screen
uniform sampler2D waterDepthTex; // terrain without water
uniform sampler2D sceneDepthTex; // terrain + water
uniform sampler2D sceneStencilTex; // custom 3d text stencils
uniform sampler2D waterHeightTex; // procedural texture for underwater
// (find more water stuff in ..water2.glsl and water_height.glsl)

uniform int viewport_width;
uniform int viewport_height;
uniform int rendMode;
uniform float time;
uniform vec3 data; // hidewater, offset, scale
uniform float daytime; // -1-0-1 night-day-night
uniform int samples;

uniform mat4 invProjection;         // Inverse projection matrix
uniform mat4 invView;               // Inverse view matrix
uniform vec3 cameraPosition;        // Camera's world position
uniform vec3 fogColor;              // Underwater fog color, e.g., vec3(0.0, 0.2, 0.3)

// Reconstruct world position from depth
//vec3 getWorldPosition(float depth, vec2 uv) {
//    float z = depth * 2.0 - 1.0; // Convert depth from [0,1] to [-1,1]
//    vec4 clipSpace = vec4(uv * 2.0 - 1.0, z, 1.0);
//    vec4 viewSpace = invProjection * clipSpace;
//    viewSpace /= viewSpace.w;    // Perspective divide
//    vec4 worldSpace = invView * viewSpace;
//    return worldSpace.xyz;
//}

// v2
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;
}

void main()
{ 
    vec2 uv = gl_FragCoord.xy / vec2(viewport_width,viewport_height);

    ivec2 vpCoords = ivec2(gl_FragCoord.x, gl_FragCoord.y);
    //////
    vec4 sample1 = texelFetch(screenTexture, vpCoords, 0);
	vec4 sample2 = texelFetch(screenTexture, vpCoords, 1);
	vec4 sample3 = texelFetch(screenTexture, vpCoords, 2);
	vec4 sample4 = texelFetch(screenTexture, vpCoords, 3);
	vec4 colorSample = (sample1 + sample2 + sample3 + sample4) / 4.0f;
    //////// do fancy post processing stuff
    
    vec3 color = vec3(colorSample.r,colorSample.g,colorSample.b);
    //vec3 color = vec3(1.0,0.0,0.0); // debug red

    float sceneDepth = texture(sceneDepthTex, uv).r;
    float waterDepth = texture(waterDepthTex, uv).r;
    float stencilDepth = texture(sceneStencilTex, uv).r;

    // sceneDepth   = terrain with water
    // waterDepth   = terrain without water
    // stencilDepth = text boxes

    float depthDiff = (waterDepth - sceneDepth)*1000;
    float stencilDiff = sceneDepth - stencilDepth;
    float edgeThreshold = .05;

    float scale=512.0;
    vec2 worldMin = vec2(-scale / 2.0, -scale / 2.0);
    vec2 worldMax = vec2(scale / 2.0, scale / 2.0);

    float wlev = data.y-1.1;
    float heightScale = data.z * 1;
    float heightOffset = wlev;

    // Sample scene color and depth
    //--vec3 color = texture(screenTexture, uv).rgb;

    vec3 debug=vec3(0.0,0.0,0.0);
    int hiddenWater = int(data.x);

    if(hiddenWater==1) {
        FragColor = vec4(color,1.0);
    } else {
        // -- underwater render itself - in water
        // Reconstruct world position of the scene point
        //vec3 P = getWorldPosition(sceneDepth - depthDiff, uv);
        //vec3 P = getWorldPosition(depthDiff, uv);
        //vec3 P = getWorldPosition(waterDepth, uv, false);
        vec3 P = getWorldPosition(sceneDepth, uv, false);
        
        vec2 waterUV = (P.xz - worldMin) / (worldMax - worldMin);
        waterUV = clamp(waterUV, 0.0, 1.0);
        //waterUV.x = 1.0-waterUV.x;
        //waterUV.y = 1.0-waterUV.y;
        //waterUV.xy = waterUV.yx;
        //P.y *= depthDiff * 1;

        // Sample water height at this (X, Z) position
        float waterHeight = texture(waterHeightTex, waterUV).r * (heightScale) + (heightOffset);
        //float dhdx = dFdx(waterHeight);
        //float dhdy = dFdy(waterHeight);

        // Check if the camera is fully underwater (using camera Y vs water height at camera's position)
        vec2 camWaterUV = (cameraPosition.xz - worldMin) / (worldMax - worldMin);
        camWaterUV = clamp(camWaterUV, 0.0, 1.0);
        float camWaterHeight = texture(waterHeightTex, camWaterUV).r * heightScale + heightOffset;

        float camDiff = camWaterHeight - cameraPosition.y;

      //  vec3 tFog = fogColor;
        // Initialize output color
        float distance = length(P - cameraPosition);
      //  float fogDistance = 50.0f;
      //  float fogHeight = 25.0;
      //  float tFac = clamp(camDiff/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.1,0.1); // day
        vec3 color2 = vec3(0.1,0.26,0.26);
        vec3 color3 = vec3(0.1,0.3,0.36); // <<day begin
        //
        vec3 color4 = vec3(0.02,0.02,0.02); // 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));

        vec3 underwaterColor = vec3(0.2, 0.6, 0.8) * (1.15-dt*1.45); // Tint
      //  //vec3 fogColor = vec3(0.1, 0.3, 0.4);
      //  //float waterDim=1.0; // surface
      //  float fogDim=1;
      //  float hdrBrightness=2.0; // 2.0
      //  float fogOffset=hdrBrightness-((fogFac*.5)+(fogDim*.5));

        bool isCameraUnderwater = camDiff > 1;
        //bool isCameraUnderwater = false;
        bool isLookingAtWaterSurface = depthDiff > 0.0 && waterDepth < 1.0; // Water in front and not at far plane
        
        float waterSurfaceFac = 0.0f;
        float terrainSurfaceFac = 0.0;
        if(isCameraUnderwater) { // fully submerged only--
            if(isLookingAtWaterSurface) { // surface from below
                if(stencilDiff < 0.0) { // stencil front of water
                    color = mix(color,underwaterColor,1.0-stencilDepth);
                    debug=vec3(0.5,0.0,0.0); // half red
                } else { // water surface
                    debug=vec3(0.0,0.0,0.5); // half blue
                    waterSurfaceFac = 1.0;
                        
                    //color = mix(fogColor, color, clamp(1.0 - (waterSurfaceFac * .3 +(distance*.01)),0.0,1.0)); // surface below
                }
            } else { // underwater render
                debug=vec3(0.0,0.25,0.0); // quart green
                terrainSurfaceFac = 1.0;

                color = mix(fogColor, color, clamp(1.0 - (terrainSurfaceFac * .4 +(distance*.045)),0.0,1.0)); // underwater fog
            }
        } else { // not entierly under water/above water
            if(stencilDiff < 0.0) { // stencil front of water
                color = mix(color,underwaterColor,1.0-stencilDepth);
                debug=vec3(1.0,0.0,0.0); // red
            } else {
                float epsilon = 0.01; // Small threshold for blending
                float underwaterFactor = smoothstep(waterHeight - epsilon, waterHeight + epsilon, P.y);

                if(underwaterFactor <= 0.0) { // below water pixel
                    if(!isLookingAtWaterSurface) {
                        debug=vec3(0.0,0.5,0.0); // half green
                        terrainSurfaceFac = 1.0;

                        // the actual underwater fog here
                        // other lines marked //---- post sshould have press pass
                        color = mix(fogColor, color, clamp(1.0 - (terrainSurfaceFac * .4 +(distance*.045)),0.0,1.0)); // overwater fog
                    } else {
                        debug=vec3(0.0,0.0,0.5); // half blue
                        waterSurfaceFac = 1.0;

                        //--color = mix(fogColor, color, clamp(1.0 - (waterSurfaceFac * .3 +(distance*.01)),0.0,1.0));
                    }
                } else { // above water pixel
                    if(!isLookingAtWaterSurface) {
                        debug=vec3(0.5,1.0,0.0); // double green
                        terrainSurfaceFac = .5;
                    } else {
                        debug=vec3(0.0,0.0,1.0); // blue
                        waterSurfaceFac = 1.0;
                
                        //--color = mix(fogColor, color, clamp(1.0 - (waterSurfaceFac * .3 +(distance*.01)),0.0,1.0));
                    }
                }
                //// Apply depth-based adjustment if needed
                //if (depthDiff/100 > 0.0) { // Water is in front
                //    underwaterFactor = min(underwaterFactor + depthDiff * 10.0, 1.0); // Fine-tune multiplier
                //}
            }
            //underwaterFactor = 1.0f; // clear for debug
        }
        //vec3 terrainFogDay = vec3(0.3,0.6,0.7);
        //vec3 terrainFogNight = vec3(0.001,0.003,0.005);
       
        // day/night terrain fog colors  blend
        color1 = vec3(0.5,0.3,0.3); // day
        color2 = vec3(0.3,0.2,0.3);
        color3 = vec3(0.3,0.2,0.2); // <<day begin
        //
        color4 = vec3(0.3,0.0,0.02); // night
        color5 = vec3(0.0,0.05,0.03);
        color6 = vec3(0.0,0.0,0.03);
 
        ourColor = vec3(mix(color3,color2,methodD));
        ourColor = mix(ourColor,color1,methodE);
        ourColor2 = vec3(mix(color5,color4,methodD));
        ourColor2 = mix(ourColor2,color6,methodE);
        vec3 terrainFogBlend = vec3(mix(ourColor,ourColor2,dt)) * (2.0-dt*4);

        float terrainFogDist = 50.0;
        float terrainFogFac = distance * terrainFogDist *.001;
        terrainFogFac=clamp(terrainFogFac,0.0,0.1);

        // consider, fog render and transparent text boxes??
        //if(distance<500.0 && stencilDiff > 0.0) { // prevent touching skybox at ~1000
        //    //----color = mix(underwaterColor, color, 1.0 - (waterSurfaceFac * .4 -.25));

        //    float epsilon = 120.0; // Small threshold for blending
        //    float terrainFogEps = smoothstep(distance - epsilon, distance + epsilon, terrainFogFac)*.4+.80; // hdr?
        //    //----color = mix(terrainFogBlend, color, terrainFogEps);
        //    //----color = mix(terrainFogBlend, color, terrainFogEps)*tFac*fogOffset;
        //} else if(stencilDiff > 0.0) {
        //    debug=vec3(0.5,0.0,0.5);
        //}
        //if(stencilDiff < 0.0) { // fog behind text/depth
        //    color *= .5;
        //}

        // Output the final color
        FragColor = vec4(color, 1.0);


        // DEBUG water
        ////if (camWaterHeight < cameraPosition.y) {
        //if (P.y < waterHeight) {
        //    FragColor = vec4(1.0, 0.0, 0.0, 1.0); // Red for underwater
        //} else {
        //    FragColor = vec4(0.0, 1.0, 0.0, 1.0); // Green for above
        //}

        //color = vec3(P.x,P.y,P.z);
        //FragColor = vec4(color, 1.0);
    }

    //// Water edge effect
    //if (depthDiff < edgeThreshold) {
    //    vec2 refractUV = uv + vec2(sin(time + uv.y * 10.0) * 0.01, 0.0); // Simple refraction
    //    ivec2 vpRef = ivec2(refractUV.x, refractUV.y);

    //    vec4 edgeColor;
    //    vec4 esample1 = texelFetch(screenTexture, vpCoords, 0);
    //    edgeColor = esample1;
    //    FragColor = mix(FragColor, edgeColor, 0.5); // Blend with edge effect
    //}

    if(rendMode==1) { 
        float single=(color.r+color.g+color.b)/3 * 2; // B/W
        float single2=0.0;
        float single3=0.0;
        //single2 *= sin(uv.x * 3.14f); // gradient sides
        single2 = depthDiff; // waterDepth - sceneDepth = green
        FragColor = vec4(single,single2,single3,1.0);
    } else if(rendMode==2) {
        float single=(color.r+color.g+color.b)/3 * 2;
        float single2=0.0;
        float single3=0.0;

        single = depthDiff; // waterDepth - sceneDepth = red
        FragColor = vec4(single,single2,single3,1.0);
    } else if(rendMode==3) {
        float single=(color.r+color.g+color.b)/3 * 2;
        float single2=0.0;
        float single3=0.0;

        single = 1.0 - stencilDiff; // sceneDepth - stencilDepth = red
        FragColor = vec4(single,single2,single3,1.0);
    } else if(rendMode==4) { // debug mode
        FragColor = vec4(debug, 1.0);
    //} else { // 0 using underwater above
        //FragColor = vec4(color,1.0);
    }
};
