#version 330 core

out vec4 color;

uniform vec4 u_Color;
uniform vec4 u_SecondColor;
uniform vec2 u_Resolution;
uniform vec2 u_Mouse;
uniform vec2 u_ViewOffset;
uniform float u_Scale;
uniform float u_ShaderScale;
uniform float u_Time;
uniform float u_Intensity;
uniform float u_Opacity;
uniform int u_Mode;

#define TAU 6.28318530718

float hash(vec2 p) {
    return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
}

float noise(vec2 p) {
    vec2 i = floor(p);
    vec2 f = fract(p);
    vec2 u = f * f * (3.0 - 2.0 * f);
    return mix(mix(hash(i), hash(i + vec2(1.0, 0.0)), u.x),
               mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), u.x), u.y);
}

float fbm(vec2 p) {
    float v = 0.0;
    float a = 0.5;
    for (int i = 0; i < 5; i++) {
        v += noise(p) * a;
        p *= 2.03;
        a *= 0.5;
    }
    return v;
}

float star(vec2 uv, float scale, float threshold) {
    vec2 p = uv * scale;
    vec2 id = floor(p);
    vec2 f = fract(p) - 0.5;
    float h = hash(id);
    float d = length(f);
    return smoothstep(0.04, 0.0, d) * step(threshold, h);
}

vec3 skyBox(vec2 uv, vec2 p, float t) {
    vec2 q = mod(uv * max(u_Scale, 0.05) * TAU, TAU) - 250.0;
    vec2 iterPos = q;
    float value = 1.0;
    for (int n = 0; n < 5; n++) {
        float iterTime = t * 0.5 + 23.0;
        iterTime *= 1.0 - (3.5 / float(n + 1));
        iterPos = q + vec2(cos(iterTime - iterPos.x) + sin(iterTime + iterPos.y),
                           sin(iterTime - iterPos.y) + cos(iterTime + iterPos.x));
        float compX = q.x * 0.005 / max(abs(sin(iterPos.x + iterTime)), 0.001);
        float compY = q.y * 0.005 / max(abs(cos(iterPos.y + iterTime)), 0.001);
        value += 1.0 / max(length(vec2(compX, compY)), 0.001);
    }
    value = 1.17 - pow(value / 5.0, 1.4);
    float pwr = value * value;
    pwr *= pwr;
    pwr *= pwr;
    float luma = dot(clamp(vec3(abs(pwr)) + vec3(0.0, 0.35, 0.5), 0.0, 1.0), vec3(0.299, 0.587, 0.114));
    return vec3(luma) * u_Color.rgb * 1.4;
}

vec3 meteor(vec2 uv, vec2 p, float t) {
    vec3 bg = mix(vec3(0.015, 0.018, 0.045), u_Color.rgb * 0.42, uv.y);
    float stars = star(uv + vec2(t * 0.01, 0.0), 150.0, 0.982) + star(uv, 260.0, 0.992);
    vec3 col = bg + stars * vec3(0.75, 0.85, 1.0);
    for (int i = 0; i < 5; i++) {
        float fi = float(i);
        vec2 m = vec2(fract(t * (0.07 + fi * 0.011) + fi * 0.23), fract(0.78 - t * (0.045 + fi * 0.007) + fi * 0.31));
        vec2 d = uv - m;
        float line = abs(d.y + d.x * 0.45);
        float along = smoothstep(0.28, -0.04, d.x) * smoothstep(-0.08, 0.22, d.x);
        float glow = smoothstep(0.022, 0.0, line) * along;
        col += glow * mix(u_SecondColor.rgb, vec3(1.0), 0.35);
    }
    return col;
}

vec3 aurora(vec2 uv, vec2 p, float t) {
    vec3 base = mix(vec3(0.005, 0.012, 0.035), u_SecondColor.rgb * 0.25, uv.y);
    float wave = sin((uv.x + fbm(uv * 3.0 + t * 0.08)) * 8.0 + t * 0.8);
    float band = smoothstep(0.18, 0.0, abs(uv.y - 0.46 - wave * 0.075));
    float band2 = smoothstep(0.22, 0.0, abs(uv.y - 0.62 + sin(uv.x * 12.0 - t) * 0.05));
    vec3 aur = u_Color.rgb * band + u_SecondColor.rgb * band2 * 0.75;
    return base + aur * (0.45 + uv.y);
}

vec3 nebula(vec2 uv, vec2 p, float t) {
    vec2 q = p * max(u_Scale, 0.25);
    float n1 = fbm(q * 2.4 + vec2(t * 0.04, -t * 0.03));
    float n2 = fbm(q * 4.2 - vec2(t * 0.02, t * 0.05));
    float cloud = smoothstep(0.25, 0.95, n1 + n2 * 0.55);
    vec3 col = mix(vec3(0.01, 0.008, 0.03), u_Color.rgb, cloud);
    col = mix(col, u_SecondColor.rgb, smoothstep(0.45, 1.0, n2) * 0.55);
    col += star(uv, 210.0, 0.988) * vec3(0.8, 0.85, 1.0);
    return col;
}

vec3 starfield(vec2 uv, vec2 p, float t) {
    vec2 drift = vec2(t * 0.015, t * 0.006);
    float s = star(uv + drift, 180.0, 0.975) + star(uv * 1.7 - drift, 240.0, 0.989);
    vec3 base = mix(vec3(0.004, 0.006, 0.018), u_Color.rgb * 0.25, uv.y);
    return base + s * mix(vec3(0.9, 0.95, 1.0), u_SecondColor.rgb, 0.35);
}

vec3 galaxy(vec2 uv, vec2 p, float t) {
    float angle = atan(p.y, p.x);
    float r = length(p);
    float arms = sin(angle * 3.0 + r * 8.0 - t * 0.35);
    float core = smoothstep(0.42, 0.02, r);
    float dust = smoothstep(0.55, 0.0, abs(arms) * r);
    vec3 col = vec3(0.006, 0.006, 0.025);
    col += u_Color.rgb * core;
    col += u_SecondColor.rgb * dust * (1.0 - smoothstep(0.05, 0.85, r));
    col += star(uv + vec2(t * 0.006, 0.0), 190.0, 0.986) * vec3(0.8, 0.88, 1.0);
    return col;
}

vec3 solidColor(vec2 uv) {
    return u_Color.rgb;
}

vec3 gradientFade(vec2 uv, float t) {
    float wave = 0.5 + 0.5 * sin((uv.y + uv.x * 0.15) * 5.0 + t * 0.6);
    float fade = smoothstep(0.0, 1.0, uv.y * 0.8 + wave * 0.2);
    vec3 base = mix(u_Color.rgb, u_SecondColor.rgb, fade);
    return base * (0.55 + 0.45 * uv.y);
}

vec3 glowingFlow(vec2 uv, vec2 p, float t) {
    vec2 q = p * max(u_Scale, 0.25);
    float n = fbm(q * 2.0 + vec2(t * 0.08, -t * 0.05));
    float flow = sin((q.x + n * 2.4) * 3.0 + t) * 0.5 + 0.5;
    vec3 col = mix(u_Color.rgb * 0.35, u_SecondColor.rgb, flow);
    col += pow(n, 3.0) * vec3(0.65, 0.75, 1.0);
    col += star(uv + vec2(t * 0.01, 0.0), 210.0, 0.988);
    return col;
}

vec3 rainbowAura(vec2 uv, vec2 p, float t) {
    float angle = atan(p.y, p.x);
    float r = length(p);
    vec3 col = 0.5 + 0.5 * cos(TAU * (vec3(0.0, 0.33, 0.67) + angle / TAU + t * 0.08));
    float aura = smoothstep(1.2, 0.05, r) * (0.55 + 0.45 * sin(r * 12.0 - t * 2.0));
    return mix(vec3(0.006, 0.007, 0.02), col, aura) + star(uv, 230.0, 0.99) * vec3(0.9);
}

vec3 cosmicHorizon(vec2 uv, vec2 p, float t) {
    vec2 q = p;
    float horizon = smoothstep(0.24, 0.0, abs(q.y + 0.08 + sin(q.x * 1.5 + t * 0.25) * 0.04));
    float glow = smoothstep(0.55, 0.0, abs(q.y + 0.05));
    vec3 col = mix(vec3(0.004, 0.006, 0.018), u_Color.rgb * 0.32, uv.y);
    col += u_SecondColor.rgb * glow * 0.28;
    col += mix(u_Color.rgb, u_SecondColor.rgb, uv.x) * horizon * 1.4;
    float dust = fbm(q * 2.6 + vec2(t * 0.04, -t * 0.03));
    col += smoothstep(0.54, 1.0, dust) * u_Color.rgb * 0.35;
    col += star(uv + vec2(t * 0.008, 0.0), 240.0, 0.986) * vec3(0.9, 0.95, 1.0);
    return col;
}

vec3 monolithFlow(vec2 uv, float t) {
    vec2 scaledUv = (uv + u_Mouse) * max(u_ShaderScale, 0.1);
    vec2 p = scaledUv * TAU - 250.0;
    vec2 iterPos = p;
    float value = 1.0;
    float timeOffset = t * 0.5 + 23.0;

    for (int n = 0; n < 5; n++) {
        float iterTime = timeOffset * (1.0 - (3.5 / float(n + 1)));
        iterPos = p + vec2(
            cos(iterTime - iterPos.x) + sin(iterTime + iterPos.y),
            sin(iterTime - iterPos.y) + cos(iterTime + iterPos.x)
        );
        float compX = p.x * max(u_Intensity, 0.001) / max(abs(sin(iterPos.x + iterTime)), 0.001);
        float compY = p.y * max(u_Intensity, 0.001) / max(abs(cos(iterPos.y + iterTime)), 0.001);
        value += 1.0 / max(length(vec2(compX, compY)), 0.001);
    }

    value = 1.17 - pow(value / 5.0, 1.4);
    float pwr = value * value;
    pwr = pwr * pwr;
    pwr = pwr * pwr;

    vec3 enhancedColor = clamp(vec3(abs(pwr)) + vec3(0.0, 0.35, 0.5), 0.0, 1.0);
    float luminance = dot(enhancedColor, vec3(0.299, 0.587, 0.114));
    vec3 gradientColor = mix(u_Color.rgb, u_SecondColor.rgb, smoothstep(0.0, 1.0, luminance));
    return vec3(luminance) * gradientColor * 1.4;
}

vec3 noxisGradientFade(vec2 frag, float t) {
    float factor = max(1.0, u_Scale * 300.0);
    float distance = (length(frag) + t * 300.0) / factor;
    distance = (sin(distance) + 1.0) * 0.5;
    float inv = 1.0 - distance;
    return u_Color.rgb * distance + u_SecondColor.rgb * inv;
}

vec3 noxisGlowingFlow(vec2 frag, float t) {
    vec2 uv = (2.0 * frag - u_Resolution.xy) / min(u_Resolution.x, u_Resolution.y);
    for (float i = 1.0; i < 10.0; i++) {
        uv.x += 0.6 / i * cos(i * 2.5 * uv.y + t);
        uv.y += 0.6 / i * cos(i * 1.5 * uv.x + t);
    }
    float wave = max(abs(sin(t - uv.y - uv.x)), 0.08);
    return clamp(u_Color.rgb / wave, 0.0, 1.6);
}

vec3 noxisRainbowAura(vec2 uv, float t) {
    vec3 offset = -3.1416 * vec3(0.0, 0.5, 1.0);
    float g = uv.y + t;
    vec3 col = 0.5 + 0.5 * -sin(g) * cos(g + offset);
    col.g += 0.25;
    col = 0.5 + (col * 2.0 - 1.0);
    col.gb *= vec2(0.75, 0.9);
    return 0.125 + 0.75 * col;
}

vec3 noxisMonolithFlow(vec2 uv, float t) {
    vec2 scaledUv = (uv + u_Mouse) * max(u_ShaderScale, 0.1);
    vec2 p = scaledUv * TAU - 250.0;
    vec2 iterPos = p;
    float value = 1.0;
    float timeOffset = t * 0.5 + 23.0;

    for (int n = 0; n < 5; n++) {
        float iterTime = timeOffset * (1.0 - (3.5 / float(n + 1)));
        iterPos = p + vec2(
            cos(iterTime - iterPos.x) + sin(iterTime + iterPos.y),
            sin(iterTime - iterPos.y) + cos(iterTime + iterPos.x)
        );

        float sinX = sin(iterPos.x + iterTime);
        float cosY = cos(iterPos.y + iterTime);
        float compX = p.x * max(u_Intensity, 0.001) / max(abs(sinX), 0.001);
        float compY = p.y * max(u_Intensity, 0.001) / max(abs(cosY), 0.001);
        value += 1.0 / max(sqrt(compX * compX + compY * compY), 0.001);
    }

    value = 1.17 - pow(value / 5.0, 1.4);
    float pwr = value * value;
    pwr = pwr * pwr;
    pwr = pwr * pwr;
    vec3 enhancedColor = clamp(vec3(abs(pwr)) + vec3(0.0, 0.35, 0.5), 0.0, 1.0);
    float luminance = dot(enhancedColor, vec3(0.299, 0.587, 0.114));
    vec3 gradientColor = mix(u_Color.rgb, u_SecondColor.rgb, smoothstep(0.0, 1.0, luminance));
    return vec3(luminance) * gradientColor * 1.4;
}

void main() {
    vec2 uv = gl_FragCoord.xy / max(u_Resolution.xy, vec2(1.0));
    vec2 p = (gl_FragCoord.xy * 2.0 - u_Resolution.xy) / max(u_Resolution.y, 1.0);
    vec2 skyUv = vec2(fract(uv.x + u_ViewOffset.x), clamp(uv.y + u_ViewOffset.y, 0.0, 1.0));
    vec2 skyFrag = skyUv * u_Resolution.xy;
    vec2 skyP = (skyFrag * 2.0 - u_Resolution.xy) / max(u_Resolution.y, 1.0);
    float t = u_Time;

    vec3 rgb;
    if (u_Mode == 1) {
        rgb = meteor(skyUv, skyP, t);
    } else if (u_Mode == 2) {
        rgb = aurora(skyUv, skyP, t);
    } else if (u_Mode == 3) {
        rgb = nebula(skyUv, skyP, t);
    } else if (u_Mode == 4) {
        rgb = starfield(skyUv, skyP, t);
    } else if (u_Mode == 5) {
        rgb = galaxy(skyUv, skyP, t);
    } else if (u_Mode == 6) {
        rgb = solidColor(uv);
    } else if (u_Mode == 7) {
        rgb = gradientFade(skyUv, t);
    } else if (u_Mode == 8) {
        rgb = glowingFlow(skyUv, skyP, t);
    } else if (u_Mode == 9) {
        rgb = rainbowAura(skyUv, skyP, t);
    } else if (u_Mode == 10) {
        rgb = cosmicHorizon(skyUv, skyP, t);
    } else if (u_Mode == 11) {
        rgb = monolithFlow(skyUv, t);
    } else if (u_Mode == 12) {
        rgb = noxisGradientFade(skyFrag, t);
    } else if (u_Mode == 13) {
        rgb = noxisGlowingFlow(skyFrag, t);
    } else if (u_Mode == 14) {
        rgb = noxisRainbowAura(skyUv, t);
    } else if (u_Mode == 15) {
        rgb = noxisMonolithFlow(skyUv, t);
    } else {
        rgb = skyBox(skyUv, skyP, t);
    }

    float alpha = max(u_Color.a * max(u_Opacity, 0.01), 0.01);
    color = vec4(clamp(rgb, 0.0, 1.6), alpha);
}
