#version 330 core
out vec4 FragColor;
in vec2 vUV;

uniform vec3 iResolution;
uniform float iTime;
uniform float uAlpha;

#define AA 2

vec2 rot(vec2 v, float t)
{
    float s = sin(t), c = cos(t);
    return mat2(c, -s, s, c) * v;
}

vec3 acesTonemap(vec3 c)
{
    mat3 m1 = mat3(0.59719, 0.07600, 0.02840, 0.35458, 0.90834, 0.13383, 0.04823, 0.01566, 0.83777);
    mat3 m2 = mat3(1.60475, -0.10208, -0.00327, -0.53108, 1.10813, -0.07276, -0.07367, -0.00605, 1.07602);
    vec3 v = m1 * c;
    vec3 aVal = v * (v + 0.0245786) - 0.000090537;
    vec3 b = v * (0.983729 * v + 0.4329510) + 0.238081;
    return m2 * (aVal / b);
}

float no(vec3 p)
{
    const float PHI = 1.618033988;
    const mat3 GOLD = mat3(
        -0.571464913,  0.814921382,  0.096597072,
        -0.278044873, -0.303026659,  0.911518454,
         0.772087367,  0.494042493,  0.399753815);
    return dot(cos(GOLD * p), sin(PHI * p * GOLD));
}

vec3 render(vec2 fragCoord)
{
    vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;

    float r = max(length(uv), 0.0001);
    float aAng = atan(uv.y, uv.x);

    float arms = 14.0;
    float rings = -6.0;
    float spiralTwistX = -5.0;
    float spiralTwistY = 12.0;

    vec2 st = vec2(
        (aAng / 6.28318530718) * arms + log(r) * spiralTwistX,
        (aAng / 6.28318530718) * rings + log(r) * spiralTwistY
    );

    vec2 stTiles = st + iTime * vec2(0.4, 0.6);
    vec2 grid = fract(stTiles);
    vec2 center = grid - 0.5;

    float dist = max(abs(center.x), abs(center.y)) * 2.0;
    float mask = smoothstep(0.98, 0.85, dist);

    vec3 normal = normalize(vec3(center.x * 2.5, center.y * 2.5, 1.0 - pow(dist, 3.0)));

    vec3 colGold = vec3(1.0, 0.7, 0.1);
    vec3 colBlue = vec3(0.0, 0.4, 1.0);
    vec3 colPurple = vec3(0.6, 0.0, 0.8);
    vec3 baseColor = mix(colGold, colBlue, smoothstep(0.0, 0.35, r));
    baseColor = mix(baseColor, colPurple, smoothstep(0.35, 1.0, r));

    vec2 liquidUVScreen = fragCoord + normal.xy * 25.0;
    vec2 luv = (liquidUVScreen - 0.5 * iResolution.xy) / iResolution.y;

    float lr = max(length(luv), 0.0001);
    float la = atan(luv.y, luv.x);
    la -= log(lr) * 2.0 + iTime * 0.5;
    vec2 swirledUV = lr * vec2(cos(la), sin(la));

    float t = iTime;
    vec3 p = vec3(0.0), l = vec3(0.0), b, d;
    p.z = -1.0 - 0.5 * sin(t * 0.1);
    d = normalize(vec3(swirledUV * 2.0, 1.0));

    float s = 0.0;
    float iStep = 0.0;

    for (int j = 0; j < 10; j++)
    {
        b = p;
        b.xy = rot(sin(b.xy * 0.25), t * 0.5 + b.z * 2.0);
        s = 0.001 + abs(no(b * 20.0) / 20.0 - no(b)) * 0.7;
        s += abs(p.y * 0.2 + sin(p.z * 2.0 + (abs(p.x) * 0.5))) * 0.5;
        p += d * s;
        l += baseColor * (1.0 + 1.5 * sin(iStep + length(p.xy * 0.1))) / s;
        iStep += 1.0;
    }

    vec3 liquidColor = acesTonemap(l * l / 400.0);
    vec3 lightDir = normalize(vec3(0.5, 0.5, 1.0));
    vec3 viewDir = vec3(0.0, 0.0, 1.0);

    float diffuse = max(dot(normal, lightDir), 0.0);
    float fresnel = pow(1.0 - max(dot(normal, viewDir), 0.0), 3.0);

    vec3 finalCol = liquidColor * (0.6 + 0.4 * diffuse);
    finalCol += baseColor * fresnel * 1.2 * mask;
    finalCol = mix(vec3(0.01, 0.01, 0.02), finalCol, mask);
    finalCol *= smoothstep(0.0, 0.15, r);
    finalCol += colGold * exp(-r * 18.0) * 2.5;

    return finalCol;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec3 color = vec3(0.0);

    for (int m = 0; m < AA; m++)
    {
        for (int n = 0; n < AA; n++)
        {
            vec2 off = (vec2(float(m), float(n)) + 0.5) / float(AA) - 0.5;
            color += render(fragCoord + off);
        }
    }

    fragColor = vec4(color / float(AA * AA), uAlpha);
}

void main()
{
    mainImage(FragColor, gl_FragCoord.xy);
}
