#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ShaderUniformKind {
    Float1,
    Float2,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ShaderUniform {
    pub name: &'static str,
    pub kind: ShaderUniformKind,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ShaderSource {
    pub name: &'static str,
    pub vertex: &'static str,
    pub fragment: &'static str,
    pub uniforms: &'static [ShaderUniform],
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ShaderFamily {
    Background,
    Panel,
    Prompt,
    Interaction,
    Code,
    AgentFlow,
    Data,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ShaderDescriptor {
    pub source: ShaderSource,
    pub family: ShaderFamily,
    pub description: &'static str,
    pub complexity: u8,
    pub animated: bool,
}

pub const COMMON_UNIFORMS: &[ShaderUniform] = &[
    ShaderUniform {
        name: "u_time",
        kind: ShaderUniformKind::Float1,
    },
    ShaderUniform {
        name: "u_resolution",
        kind: ShaderUniformKind::Float2,
    },
    ShaderUniform {
        name: "u_intensity",
        kind: ShaderUniformKind::Float1,
    },
];

pub const VERTEX: &str = r#"#version 100
attribute vec3 position;
attribute vec2 texcoord;
attribute vec4 color0;
varying lowp vec2 uv;
varying lowp vec4 color;
uniform mat4 Model;
uniform mat4 Projection;
void main() {
    gl_Position = Projection * Model * vec4(position, 1.0);
    uv = texcoord;
    color = color0;
}
"#;

pub const BACKGROUND_FRAGMENT: &str = r#"#version 100
precision mediump float;
varying lowp vec2 uv;
varying lowp vec4 color;
uniform sampler2D Texture;
uniform float u_time;
uniform vec2 u_resolution;
uniform float u_intensity;

float hash(vec2 p) {
    p = fract(p * vec2(123.34, 456.21));
    p += dot(p, p + 45.32);
    return fract(p.x * p.y);
}

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 + vec2(0.0, 0.0)), 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 value = 0.0;
    float amplitude = 0.5;
    mat2 warp = mat2(1.62, 1.18, -1.18, 1.62);
    for (int i = 0; i < 6; i++) {
        value += amplitude * noise(p);
        p = warp * p + vec2(0.17, 0.31);
        amplitude *= 0.53;
    }
    return value;
}

vec2 curl(vec2 p) {
    float e = 0.035;
    float n1 = fbm(p + vec2(0.0, e));
    float n2 = fbm(p - vec2(0.0, e));
    float n3 = fbm(p + vec2(e, 0.0));
    float n4 = fbm(p - vec2(e, 0.0));
    return vec2(n1 - n2, n4 - n3) / (2.0 * e);
}

float rings(vec2 p, float t) {
    float d = length(p);
    float wave = sin(34.0 * d - t * 3.5 + fbm(p * 4.0) * 2.5);
    return smoothstep(0.84, 1.0, wave) * smoothstep(1.2, 0.12, d);
}

void main() {
    vec2 p = (gl_FragCoord.xy * 2.0 - u_resolution.xy) / max(u_resolution.x, u_resolution.y);
    float t = u_time * 0.18;
    vec2 flow = curl(p * 2.0 + t);
    vec2 q = p + flow * 0.22 + vec2(sin(t * 1.7), cos(t * 1.3)) * 0.08;
    float nebula = fbm(q * 2.6 + t * 0.7);
    float veins = fbm(q * 9.0 - flow * 1.4);
    float halo = rings(p - vec2(0.38, -0.2), u_time);
    float vignette = smoothstep(1.36, 0.18, length(p));
    vec3 ink = vec3(0.010, 0.014, 0.034);
    vec3 blue = vec3(0.09, 0.32, 0.78);
    vec3 cyan = vec3(0.12, 0.82, 1.0);
    vec3 violet = vec3(0.56, 0.14, 0.96);
    vec3 gold = vec3(1.0, 0.55, 0.17);
    vec3 col = ink;
    col += blue * nebula * 0.34;
    col += cyan * smoothstep(0.52, 0.96, veins) * 0.24;
    col += violet * pow(max(nebula, 0.0), 2.2) * 0.32;
    col += gold * halo * 0.36;
    col *= 0.55 + vignette * 0.75;
    col += vec3(hash(gl_FragCoord.xy + u_time) * 0.025);
    gl_FragColor = vec4(col * (0.72 + u_intensity * 0.42), 1.0) * color;
}
"#;

pub const PANE_FRAGMENT: &str = r#"#version 100
precision mediump float;
varying lowp vec2 uv;
varying lowp vec4 color;
uniform sampler2D Texture;
uniform float u_time;
uniform vec2 u_resolution;
uniform float u_intensity;

float hex(vec2 p) {
    p.x *= 0.57735 * 2.0;
    p.y += mod(floor(p.x), 2.0) * 0.5;
    p = abs(fract(p) - 0.5);
    return abs(max(p.x * 1.5 + p.y, p.y * 2.0) - 1.0);
}

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

float grid(vec2 p, float t) {
    vec2 id = floor(p);
    float h = hash(id);
    float cell = smoothstep(0.035, 0.0, hex(p));
    float sweep = smoothstep(0.98, 0.4, abs(fract(h + t * 0.08) - 0.5));
    return cell * sweep;
}

void main() {
    vec2 p = uv;
    vec2 centered = p - 0.5;
    float edge = smoothstep(0.5, 0.47, max(abs(centered.x), abs(centered.y)));
    float border = 1.0 - smoothstep(0.0, 0.018, min(min(p.x, p.y), min(1.0 - p.x, 1.0 - p.y)));
    float lattice = grid((p + vec2(u_time * 0.018, -u_time * 0.012)) * 18.0, u_time);
    float scan = sin((p.y + u_time * 0.11) * 420.0) * 0.5 + 0.5;
    vec3 base = vec3(0.018, 0.032, 0.070);
    vec3 glow = vec3(0.10, 0.54, 0.95) * lattice * 0.22;
    vec3 rim = vec3(0.36, 0.76, 1.0) * border * (0.32 + 0.22 * sin(u_time * 1.9));
    vec3 col = base + glow + rim + vec3(scan * 0.018 * u_intensity);
    gl_FragColor = vec4(col, 0.82 * edge) * color;
}
"#;

pub const PROMPT_FRAGMENT: &str = r#"#version 100
precision mediump float;
varying lowp vec2 uv;
varying lowp vec4 color;
uniform sampler2D Texture;
uniform float u_time;
uniform vec2 u_resolution;
uniform float u_intensity;

float line(vec2 p, float offset, float width) {
    return smoothstep(width, 0.0, abs(p.y - offset));
}

void main() {
    vec2 p = uv;
    float t = u_time;
    float beam = line(p, 0.5 + sin(t * 1.4 + p.x * 7.0) * 0.08, 0.018);
    float beam2 = line(p, 0.34 + cos(t * 1.1 + p.x * 9.0) * 0.05, 0.012);
    float edge = 1.0 - smoothstep(0.0, 0.026, min(min(p.x, p.y), min(1.0 - p.x, 1.0 - p.y)));
    float caret = smoothstep(0.015, 0.0, abs(fract(p.x * 34.0 - t * 0.9) - 0.5));
    vec3 base = vec3(0.020, 0.030, 0.070);
    vec3 cyan = vec3(0.16, 0.86, 1.0);
    vec3 violet = vec3(0.75, 0.24, 1.0);
    vec3 col = base + cyan * beam * 0.28 + violet * beam2 * 0.18;
    col += cyan * edge * 0.32;
    col += vec3(0.35, 0.85, 1.0) * caret * 0.035 * u_intensity;
    gl_FragColor = vec4(col, 0.90) * color;
}
"#;

pub const AURORA_FRAGMENT: &str = r#"#version 100
precision mediump float;
varying lowp vec2 uv;
varying lowp vec4 color;
uniform sampler2D Texture;
uniform float u_time;
uniform vec2 u_resolution;
uniform float u_intensity;

float hash(vec2 p) {
    return fract(sin(dot(p, vec2(41.0, 289.0))) * 45758.5453);
}

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

float ridge(float v) {
    return 1.0 - abs(v * 2.0 - 1.0);
}

void main() {
    vec2 p = (gl_FragCoord.xy / u_resolution.xy);
    float t = u_time * 0.12;
    float curtain = 0.0;
    for (int i = 0; i < 5; i++) {
        float fi = float(i);
        vec2 q = vec2(p.x * (2.0 + fi * 0.65) + t * (0.7 + fi * 0.13), p.y * (7.0 + fi));
        float band = ridge(noise(q + vec2(fi * 8.7, -t * 2.0)));
        curtain += smoothstep(0.44, 1.0, band) * (0.18 + fi * 0.035);
    }
    float horizon = smoothstep(0.98, 0.16, p.y);
    float stars = step(0.996, hash(gl_FragCoord.xy + floor(u_time * 8.0))) * smoothstep(0.8, 0.05, p.y);
    vec3 deep = vec3(0.005, 0.015, 0.042);
    vec3 green = vec3(0.18, 1.00, 0.70);
    vec3 blue = vec3(0.10, 0.42, 1.00);
    vec3 magenta = vec3(0.85, 0.16, 1.00);
    vec3 col = deep + mix(blue, green, p.y) * curtain * horizon * u_intensity;
    col += magenta * pow(curtain, 3.0) * 0.18;
    col += vec3(stars) * 0.75;
    gl_FragColor = vec4(col, 1.0) * color;
}
"#;

pub const KNOT_FIELD_FRAGMENT: &str = r#"#version 100
precision mediump float;
varying lowp vec2 uv;
varying lowp vec4 color;
uniform sampler2D Texture;
uniform float u_time;
uniform vec2 u_resolution;
uniform float u_intensity;

float sdTorus(vec3 p, vec2 t) {
    vec2 q = vec2(length(p.xz) - t.x, p.y);
    return length(q) - t.y;
}

mat2 rot(float a) {
    float s = sin(a);
    float c = cos(a);
    return mat2(c, -s, s, c);
}

float field(vec3 p) {
    p.xz *= rot(u_time * 0.23);
    p.xy *= rot(sin(u_time * 0.17) * 0.6);
    float d = sdTorus(p, vec2(0.62, 0.055));
    vec3 q = p;
    q.xy *= rot(2.094);
    float d2 = sdTorus(q, vec2(0.62, 0.055));
    q = p;
    q.xy *= rot(-2.094);
    float d3 = sdTorus(q, vec2(0.62, 0.055));
    return min(d, min(d2, d3));
}

void main() {
    vec2 p = (gl_FragCoord.xy * 2.0 - u_resolution.xy) / max(u_resolution.x, u_resolution.y);
    vec3 ro = vec3(0.0, 0.0, 2.1);
    vec3 rd = normalize(vec3(p, -1.65));
    float t = 0.0;
    float glow = 0.0;
    float hit = 0.0;
    for (int i = 0; i < 58; i++) {
        vec3 pos = ro + rd * t;
        float d = field(pos);
        glow += 0.006 / (0.018 + abs(d));
        if (d < 0.003) {
            hit = 1.0;
            break;
        }
        t += max(d * 0.58, 0.012);
        if (t > 4.0) {
            break;
        }
    }
    vec3 base = vec3(0.005, 0.010, 0.025);
    vec3 cyan = vec3(0.10, 0.78, 1.00);
    vec3 violet = vec3(0.65, 0.14, 1.00);
    vec3 gold = vec3(1.00, 0.48, 0.10);
    vec3 col = base + cyan * glow * 0.24 + violet * pow(glow, 1.4) * 0.08 + gold * hit * 0.35;
    col *= 0.74 + u_intensity * 0.34;
    gl_FragColor = vec4(col, 0.96) * color;
}
"#;

pub const TERMINAL_RAIN_FRAGMENT: &str = r#"#version 100
precision mediump float;
varying lowp vec2 uv;
varying lowp vec4 color;
uniform sampler2D Texture;
uniform float u_time;
uniform vec2 u_resolution;
uniform float u_intensity;

float hash(vec2 p) {
    return fract(sin(dot(p, vec2(13.13, 91.77))) * 43758.5453);
}

void main() {
    vec2 cell = floor(gl_FragCoord.xy / vec2(10.0, 18.0));
    float column = hash(vec2(cell.x, 2.0));
    float speed = mix(0.8, 3.4, column);
    float trail = fract(cell.y * 0.071 - u_time * speed + column * 9.0);
    float glyph = hash(cell + floor(u_time * speed));
    float on = smoothstep(0.92, 1.0, trail) * step(0.22, glyph);
    float tail = smoothstep(0.45, 0.0, trail) * step(0.65, column);
    vec3 base = vec3(0.0, 0.012, 0.025);
    vec3 green = vec3(0.18, 1.0, 0.56);
    vec3 blue = vec3(0.1, 0.68, 1.0);
    vec3 col = base + green * on * u_intensity + blue * tail * 0.18;
    col += vec3(hash(gl_FragCoord.xy) * 0.018);
    gl_FragColor = vec4(col, 0.72) * color;
}
"#;

pub const AGENT_FLOW_FRAGMENT: &str = r#"#version 100
precision mediump float;
varying lowp vec2 uv;
varying lowp vec4 color;
uniform sampler2D Texture;
uniform float u_time;
uniform vec2 u_resolution;
uniform float u_intensity;

float capsule(vec2 p, vec2 a, vec2 b, float r) {
    vec2 pa = p - a;
    vec2 ba = b - a;
    float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
    return length(pa - ba * h) - r;
}

void main() {
    vec2 p = uv;
    float glow = 0.0;
    for (int i = 0; i < 7; i++) {
        float fi = float(i);
        vec2 a = vec2(0.08, 0.16 + fi * 0.115);
        vec2 b = vec2(0.92, 0.22 + sin(u_time * 0.7 + fi) * 0.24 + fi * 0.08);
        float d = capsule(p, a, b, 0.006 + 0.002 * sin(u_time + fi));
        float pulse = smoothstep(0.05, 0.0, abs(fract(u_time * 0.22 + fi * 0.17) - p.x));
        glow += smoothstep(0.028, 0.0, d) * (0.28 + pulse * 0.72);
    }
    float node = 0.0;
    for (int j = 0; j < 5; j++) {
        float fj = float(j);
        vec2 c = vec2(0.16 + fj * 0.18, 0.5 + sin(u_time * 0.5 + fj * 1.7) * 0.28);
        node += smoothstep(0.06, 0.0, length(p - c));
    }
    vec3 base = vec3(0.014, 0.020, 0.050);
    vec3 cyan = vec3(0.08, 0.80, 1.00);
    vec3 violet = vec3(0.62, 0.16, 1.00);
    vec3 col = base + cyan * glow * 0.45 * u_intensity + violet * node * 0.20;
    gl_FragColor = vec4(col, 0.86) * color;
}
"#;

pub const RIPPLE_FRAGMENT: &str = r#"#version 100
precision mediump float;
varying lowp vec2 uv;
varying lowp vec4 color;
uniform sampler2D Texture;
uniform float u_time;
uniform vec2 u_resolution;
uniform float u_intensity;

float ring(vec2 p, vec2 c, float radius, float width) {
    float d = length(p - c);
    return smoothstep(width, 0.0, abs(d - radius));
}

float disk(vec2 p, vec2 c, float radius) {
    return smoothstep(radius, 0.0, length(p - c));
}

void main() {
    vec2 p = uv;
    float t = fract(u_time * 0.62);
    vec2 c1 = vec2(0.30 + sin(u_time * 0.37) * 0.09, 0.50 + cos(u_time * 0.41) * 0.08);
    vec2 c2 = vec2(0.70 + cos(u_time * 0.29) * 0.11, 0.46 + sin(u_time * 0.53) * 0.10);
    float r1 = ring(p, c1, t * 0.72, 0.026) * (1.0 - t);
    float r2 = ring(p, c2, fract(t + 0.38) * 0.66, 0.020) * (1.0 - fract(t + 0.38));
    float ink = disk(p, c1, 0.12 + t * 0.5) * 0.055 + disk(p, c2, 0.10 + fract(t + 0.38) * 0.45) * 0.045;
    float border = 1.0 - smoothstep(0.0, 0.018, min(min(p.x, p.y), min(1.0 - p.x, 1.0 - p.y)));
    vec3 base = vec3(0.018, 0.026, 0.055);
    vec3 cyan = vec3(0.12, 0.82, 1.0);
    vec3 violet = vec3(0.72, 0.20, 1.0);
    vec3 col = base + cyan * r1 * u_intensity + violet * r2 * 0.72 * u_intensity + cyan * border * 0.22 + vec3(ink);
    gl_FragColor = vec4(col, 0.82) * color;
}
"#;

pub const BLOOM_GLOW_FRAGMENT: &str = r#"#version 100
precision mediump float;
varying lowp vec2 uv;
varying lowp vec4 color;
uniform sampler2D Texture;
uniform float u_time;
uniform vec2 u_resolution;
uniform float u_intensity;

float blob(vec2 p, vec2 c, float radius) {
    float d = length(p - c);
    return radius * radius / max(d * d, 0.001);
}

void main() {
    vec2 p = uv;
    float t = u_time;
    float glow = 0.0;
    glow += blob(p, vec2(0.22 + sin(t * 0.7) * 0.12, 0.34 + cos(t * 0.6) * 0.08), 0.045);
    glow += blob(p, vec2(0.76 + cos(t * 0.5) * 0.10, 0.52 + sin(t * 0.9) * 0.12), 0.060);
    glow += blob(p, vec2(0.50 + sin(t * 0.4) * 0.18, 0.78 + cos(t * 0.8) * 0.05), 0.038);
    glow = min(glow, 3.0);
    float scan = sin((p.y + t * 0.11) * 540.0) * 0.5 + 0.5;
    float vignette = smoothstep(0.82, 0.12, length(p - 0.5));
    vec3 base = vec3(0.010, 0.014, 0.030);
    vec3 hot = mix(vec3(0.10, 0.55, 1.0), vec3(0.95, 0.18, 1.0), p.x);
    vec3 col = base + hot * glow * 0.23 * u_intensity + vec3(scan * 0.018);
    col *= 0.62 + vignette * 0.72;
    gl_FragColor = vec4(col, 0.78) * color;
}
"#;

pub const CODE_LENS_FRAGMENT: &str = r#"#version 100
precision mediump float;
varying lowp vec2 uv;
varying lowp vec4 color;
uniform sampler2D Texture;
uniform float u_time;
uniform vec2 u_resolution;
uniform float u_intensity;

float hash(vec2 p) {
    return fract(sin(dot(p, vec2(101.7, 203.3))) * 43758.5453);
}

float line_y(float y, float target, float width) {
    return smoothstep(width, 0.0, abs(y - target));
}

void main() {
    vec2 p = uv;
    float lens = smoothstep(0.38, 0.0, length((p - vec2(0.5, 0.52)) * vec2(1.0, 1.8)));
    float code = 0.0;
    for (int i = 0; i < 18; i++) {
        float fi = float(i);
        float y = 0.08 + fi * 0.048;
        float len = 0.2 + hash(vec2(fi, 1.0)) * 0.58;
        float start = 0.08 + hash(vec2(fi, 2.0)) * 0.18;
        float seg = smoothstep(start, start + 0.018, p.x) * smoothstep(start + len, start + len - 0.018, p.x);
        code += line_y(p.y, y + sin(u_time * 0.9 + fi) * 0.003, 0.004 + lens * 0.006) * seg;
    }
    float cursor = smoothstep(0.015, 0.0, abs(p.x - (0.16 + fract(u_time * 0.11) * 0.68))) * line_y(p.y, 0.52, 0.022);
    vec3 base = vec3(0.012, 0.017, 0.034);
    vec3 text = vec3(0.52, 0.85, 1.0);
    vec3 lens_col = vec3(0.18, 0.58, 1.0) * lens * 0.18;
    vec3 col = base + text * code * (0.22 + lens * 0.50) * u_intensity + lens_col + vec3(0.9, 0.6, 0.2) * cursor * 0.6;
    gl_FragColor = vec4(col, 0.86) * color;
}
"#;

pub const REACTION_DIFFUSION_FRAGMENT: &str = r#"#version 100
precision mediump float;
varying lowp vec2 uv;
varying lowp vec4 color;
uniform sampler2D Texture;
uniform float u_time;
uniform vec2 u_resolution;
uniform float u_intensity;

float hash(vec2 p) {
    return fract(sin(dot(p, vec2(17.17, 313.13))) * 43758.5453);
}

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

void main() {
    vec2 p = (gl_FragCoord.xy * 2.0 - u_resolution.xy) / max(u_resolution.x, u_resolution.y);
    float t = u_time * 0.12;
    float a = n(p * 4.0 + t);
    float b = n(p * 9.0 - t * 1.7 + a);
    float c = n(p * 19.0 + vec2(a, b) * 3.0 - t);
    float cells = smoothstep(0.48, 0.54, abs(a - b) + c * 0.14);
    float veins = smoothstep(0.72, 0.98, sin((a - b + c) * 18.0 + u_time));
    vec3 base = vec3(0.008, 0.014, 0.028);
    vec3 acid = vec3(0.30, 1.0, 0.58);
    vec3 plasma = vec3(0.45, 0.18, 1.0);
    vec3 col = base + acid * cells * 0.32 * u_intensity + plasma * veins * 0.26;
    gl_FragColor = vec4(col, 0.80) * color;
}
"#;

pub const VORONOI_CRYSTAL_FRAGMENT: &str = r#"#version 100
precision mediump float;
varying lowp vec2 uv;
varying lowp vec4 color;
uniform sampler2D Texture;
uniform float u_time;
uniform vec2 u_resolution;
uniform float u_intensity;

vec2 hash2(vec2 p) {
    p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3)));
    return fract(sin(p) * 43758.5453);
}

void main() {
    vec2 p = uv * vec2(u_resolution.x / max(u_resolution.y, 1.0), 1.0) * 8.0;
    vec2 i = floor(p);
    vec2 f = fract(p);
    float min_d = 8.0;
    float second_d = 8.0;
    for (int y = -1; y <= 1; y++) {
        for (int x = -1; x <= 1; x++) {
            vec2 g = vec2(float(x), float(y));
            vec2 o = hash2(i + g);
            o = 0.5 + 0.5 * sin(u_time * 0.35 + 6.2831 * o);
            float d = length(g + o - f);
            if (d < min_d) {
                second_d = min_d;
                min_d = d;
            } else if (d < second_d) {
                second_d = d;
            }
        }
    }
    float edge = smoothstep(0.045, 0.0, second_d - min_d);
    float facet = smoothstep(0.9, 0.0, min_d);
    vec3 base = vec3(0.010, 0.012, 0.032);
    vec3 cyan = vec3(0.18, 0.82, 1.0);
    vec3 rose = vec3(1.0, 0.20, 0.62);
    vec3 col = base + cyan * edge * 0.58 * u_intensity + rose * facet * 0.10;
    gl_FragColor = vec4(col, 0.78) * color;
}
"#;

pub const PLASMA_GRAPH_FRAGMENT: &str = r#"#version 100
precision mediump float;
varying lowp vec2 uv;
varying lowp vec4 color;
uniform sampler2D Texture;
uniform float u_time;
uniform vec2 u_resolution;
uniform float u_intensity;

float line(vec2 p, vec2 a, vec2 b, float w) {
    vec2 pa = p - a;
    vec2 ba = b - a;
    float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
    return smoothstep(w, 0.0, length(pa - ba * h));
}

void main() {
    vec2 p = uv;
    vec2 nodes[6];
    nodes[0] = vec2(0.14, 0.25 + sin(u_time * 0.8) * 0.06);
    nodes[1] = vec2(0.32, 0.68 + cos(u_time * 0.5) * 0.07);
    nodes[2] = vec2(0.48, 0.36 + sin(u_time * 0.6 + 1.0) * 0.08);
    nodes[3] = vec2(0.64, 0.72 + cos(u_time * 0.7 + 2.0) * 0.06);
    nodes[4] = vec2(0.82, 0.30 + sin(u_time * 0.55 + 3.0) * 0.07);
    nodes[5] = vec2(0.90, 0.82 + cos(u_time * 0.45 + 4.0) * 0.05);
    float network = 0.0;
    float sparks = 0.0;
    for (int i = 0; i < 5; i++) {
        vec2 a = nodes[i];
        vec2 b = nodes[i + 1];
        network += line(p, a, b, 0.010);
        float pulse = fract(u_time * 0.22 + float(i) * 0.19);
        sparks += smoothstep(0.045, 0.0, length(p - mix(a, b, pulse)));
    }
    for (int j = 0; j < 6; j++) {
        network += smoothstep(0.055, 0.0, length(p - nodes[j])) * 0.9;
    }
    vec3 base = vec3(0.007, 0.010, 0.028);
    vec3 blue = vec3(0.10, 0.58, 1.0);
    vec3 hot = vec3(1.0, 0.36, 0.12);
    vec3 col = base + blue * network * 0.34 * u_intensity + hot * sparks * 0.42;
    gl_FragColor = vec4(col, 0.84) * color;
}
"#;

pub fn background_shader() -> ShaderSource {
    ShaderSource {
        name: "rae-background-curl-nebula",
        vertex: VERTEX,
        fragment: BACKGROUND_FRAGMENT,
        uniforms: COMMON_UNIFORMS,
    }
}

pub fn pane_shader() -> ShaderSource {
    ShaderSource {
        name: "rae-pane-hex-lattice",
        vertex: VERTEX,
        fragment: PANE_FRAGMENT,
        uniforms: COMMON_UNIFORMS,
    }
}

pub fn prompt_shader() -> ShaderSource {
    ShaderSource {
        name: "rae-prompt-beam-field",
        vertex: VERTEX,
        fragment: PROMPT_FRAGMENT,
        uniforms: COMMON_UNIFORMS,
    }
}

pub fn aurora_shader() -> ShaderSource {
    ShaderSource {
        name: "rae-background-aurora-curtains",
        vertex: VERTEX,
        fragment: AURORA_FRAGMENT,
        uniforms: COMMON_UNIFORMS,
    }
}

pub fn knot_field_shader() -> ShaderSource {
    ShaderSource {
        name: "rae-knot-raymarch-field",
        vertex: VERTEX,
        fragment: KNOT_FIELD_FRAGMENT,
        uniforms: COMMON_UNIFORMS,
    }
}

pub fn terminal_rain_shader() -> ShaderSource {
    ShaderSource {
        name: "rae-terminal-rain",
        vertex: VERTEX,
        fragment: TERMINAL_RAIN_FRAGMENT,
        uniforms: COMMON_UNIFORMS,
    }
}

pub fn agent_flow_shader() -> ShaderSource {
    ShaderSource {
        name: "rae-agent-flow-beams",
        vertex: VERTEX,
        fragment: AGENT_FLOW_FRAGMENT,
        uniforms: COMMON_UNIFORMS,
    }
}

pub fn ripple_shader() -> ShaderSource {
    ShaderSource {
        name: "rae-interaction-ripples",
        vertex: VERTEX,
        fragment: RIPPLE_FRAGMENT,
        uniforms: COMMON_UNIFORMS,
    }
}

pub fn bloom_glow_shader() -> ShaderSource {
    ShaderSource {
        name: "rae-bloom-glow-field",
        vertex: VERTEX,
        fragment: BLOOM_GLOW_FRAGMENT,
        uniforms: COMMON_UNIFORMS,
    }
}

pub fn code_lens_shader() -> ShaderSource {
    ShaderSource {
        name: "rae-code-lens-scan",
        vertex: VERTEX,
        fragment: CODE_LENS_FRAGMENT,
        uniforms: COMMON_UNIFORMS,
    }
}

pub fn reaction_diffusion_shader() -> ShaderSource {
    ShaderSource {
        name: "rae-reaction-diffusion",
        vertex: VERTEX,
        fragment: REACTION_DIFFUSION_FRAGMENT,
        uniforms: COMMON_UNIFORMS,
    }
}

pub fn voronoi_crystal_shader() -> ShaderSource {
    ShaderSource {
        name: "rae-voronoi-crystal",
        vertex: VERTEX,
        fragment: VORONOI_CRYSTAL_FRAGMENT,
        uniforms: COMMON_UNIFORMS,
    }
}

pub fn plasma_graph_shader() -> ShaderSource {
    ShaderSource {
        name: "rae-plasma-graph",
        vertex: VERTEX,
        fragment: PLASMA_GRAPH_FRAGMENT,
        uniforms: COMMON_UNIFORMS,
    }
}

pub fn all_shaders() -> Vec<ShaderSource> {
    vec![
        background_shader(),
        pane_shader(),
        prompt_shader(),
        aurora_shader(),
        knot_field_shader(),
        terminal_rain_shader(),
        agent_flow_shader(),
        ripple_shader(),
        bloom_glow_shader(),
        code_lens_shader(),
        reaction_diffusion_shader(),
        voronoi_crystal_shader(),
        plasma_graph_shader(),
    ]
}

pub fn shader_catalog() -> Vec<ShaderDescriptor> {
    vec![
        ShaderDescriptor {
            source: background_shader(),
            family: ShaderFamily::Background,
            description: "Curl-noise nebula with ring interference for full-window depth.",
            complexity: 7,
            animated: true,
        },
        ShaderDescriptor {
            source: pane_shader(),
            family: ShaderFamily::Panel,
            description: "Hex lattice pane surface with scanning rim light.",
            complexity: 4,
            animated: true,
        },
        ShaderDescriptor {
            source: prompt_shader(),
            family: ShaderFamily::Prompt,
            description: "Prompt beam field with animated caret energy.",
            complexity: 3,
            animated: true,
        },
        ShaderDescriptor {
            source: aurora_shader(),
            family: ShaderFamily::Background,
            description: "Layered aurora curtains for context and reference views.",
            complexity: 5,
            animated: true,
        },
        ShaderDescriptor {
            source: knot_field_shader(),
            family: ShaderFamily::Data,
            description: "Raymarched torus-knot field for high-energy agent state.",
            complexity: 9,
            animated: true,
        },
        ShaderDescriptor {
            source: terminal_rain_shader(),
            family: ShaderFamily::Code,
            description: "Terminal rain data stream for run and log surfaces.",
            complexity: 3,
            animated: true,
        },
        ShaderDescriptor {
            source: agent_flow_shader(),
            family: ShaderFamily::AgentFlow,
            description: "Animated routed beam network for agent-flow lanes.",
            complexity: 5,
            animated: true,
        },
        ShaderDescriptor {
            source: ripple_shader(),
            family: ShaderFamily::Interaction,
            description: "Material-style click ripple field with two animated origins.",
            complexity: 4,
            animated: true,
        },
        ShaderDescriptor {
            source: bloom_glow_shader(),
            family: ShaderFamily::Interaction,
            description: "Soft bloom blobs for hover, focus, and elevated surfaces.",
            complexity: 4,
            animated: true,
        },
        ShaderDescriptor {
            source: code_lens_shader(),
            family: ShaderFamily::Code,
            description: "Code-line lens shimmer for transcript/code panes.",
            complexity: 5,
            animated: true,
        },
        ShaderDescriptor {
            source: reaction_diffusion_shader(),
            family: ShaderFamily::Background,
            description: "Procedural reaction-diffusion cells for organic loading states.",
            complexity: 6,
            animated: true,
        },
        ShaderDescriptor {
            source: voronoi_crystal_shader(),
            family: ShaderFamily::Panel,
            description: "Voronoi crystal facets for glassy command-palette surfaces.",
            complexity: 6,
            animated: true,
        },
        ShaderDescriptor {
            source: plasma_graph_shader(),
            family: ShaderFamily::AgentFlow,
            description: "Plasma graph nodes and sparks for validation/loop visualizers.",
            complexity: 6,
            animated: true,
        },
    ]
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn shader_catalog_names_are_unique() {
        let shaders = all_shaders();
        let mut names = shaders.iter().map(|shader| shader.name).collect::<Vec<_>>();
        names.sort_unstable();
        names.dedup();

        assert_eq!(names.len(), shaders.len());
    }

    #[test]
    fn all_shaders_expose_common_uniforms() {
        for shader in all_shaders() {
            assert_eq!(shader.uniforms, COMMON_UNIFORMS);
        }
    }

    #[test]
    fn descriptor_catalog_matches_sources() {
        let descriptors = shader_catalog();
        let sources = all_shaders();

        assert_eq!(descriptors.len(), sources.len());
        assert!(descriptors
            .iter()
            .all(|descriptor| descriptor.complexity > 0));
    }
}
