// Neural CSS - Fragment Shader
// SDF-based raymarching with neural materials

precision highp float;

varying vec2 vUv;
uniform float uTime;
uniform vec2 uResolution;
uniform vec3 uCameraPos;
uniform vec3 uCameraDir;
uniform mat4 uCameraMatrix;
uniform sampler2D uNeuralMap;

#define MAX_STEPS 128
#define MAX_DIST 100.0
#define SURF_DIST 0.001
#define PI 3.14159265359

// ============ SDF PRIMITIVES ============

float sdSphere(vec3 p, float r) {
    return length(p) - r;
}

float sdBox(vec3 p, vec3 b) {
    vec3 q = abs(p) - b;
    return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
}

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

float sdCylinder(vec3 p, float h, float r) {
    vec2 d = abs(vec2(length(p.xz), p.y)) - vec2(r, h);
    return min(max(d.x, d.y), 0.0) + length(max(d, 0.0));
}

// ============ NEURAL MATERIAL SYSTEM ============

struct Material {
    vec3 albedo;
    float metallic;
    float roughness;
    float emissive;
    float transparency;
    vec3 normal;
};

Material defaultMaterial() {
    Material m;
    m.albedo = vec3(0.8, 0.2, 0.3);
    m.metallic = 0.0;
    m.roughness = 0.5;
    m.emissive = 0.0;
    m.transparency = 0.0;
    m.normal = vec3(0.0, 1.0, 0.0);
    return m;
}

// ============ SCENE ============

// Multi-material SDF scene
float sceneSDF(vec3 p, out Material mat) {
    mat = defaultMaterial();
    
    float d = MAX_DIST;
    
    // Ground plane with grid
    float ground = p.y + 1.0;
    if (ground < d) {
        d = ground;
        mat.albedo = vec3(0.1, 0.1, 0.15);
        mat.metallic = 0.8;
        mat.roughness = 0.2;
        
        // Grid pattern from CSS
        vec2 grid = abs(fract(p.xz) - 0.5);
        float line = smoothstep(0.48, 0.5, max(grid.x, grid.y));
        mat.albedo += vec3(0.0, 0.8, 1.0) * line * 0.5;
    }
    
    // Animated spheres (neural-orbs from CSS)
    for (int i = 0; i < 5; i++) {
        float fi = float(i);
        vec3 spherePos = vec3(
            sin(uTime * 0.5 + fi * 1.5) * 3.0,
            cos(uTime * 0.3 + fi * 2.0) * 0.5 + 0.5,
            cos(uTime * 0.7 + fi * 1.0) * 3.0
        );
        float sphere = sdSphere(p - spherePos, 0.4 + fi * 0.1);
        
        if (sphere < d) {
            d = sphere;
            mat.albedo = vec3(
                0.5 + 0.5 * sin(fi * 2.0),
                0.5 + 0.5 * sin(fi * 2.0 + PI * 0.66),
                0.5 + 0.5 * sin(fi * 2.0 + PI * 1.33)
            );
            mat.emissive = 0.3;
            mat.metallic = 0.9;
            mat.roughness = 0.1;
        }
    }
    
    // Central complex structure
    vec3 structPos = p - vec3(0.0, 0.3, 0.0);
    float structure = min(
        sdBox(structPos, vec3(0.8, 0.1, 0.8)),
        sdTorus(structPos, vec2(0.6, 0.1))
    );
    
    // Add detail with octahedron
    float octDetail = sdSphere(mod(structPos + 0.5, 1.0) - 0.5, 0.2) - 0.05;
    structure = min(structure, octDetail);
    
    if (structure < d) {
        d = structure;
        mat.albedo = vec3(0.9, 0.9, 1.0);
        mat.metallic = 1.0;
        mat.roughness = 0.05;
        mat.emissive = 0.1 * (0.5 + 0.5 * sin(uTime * 2.0));
    }
    
    return d;
}

// ============ RAYMARCHING ============

float rayMarch(vec3 ro, vec3 rd, out Material mat) {
    float d = 0.0;
    
    for (int i = 0; i < MAX_STEPS; i++) {
        vec3 p = ro + rd * d;
        float ds = sceneSDF(p, mat);
        d += ds;
        if (ds < SURF_DIST || d > MAX_DIST) break;
    }
    
    return d;
}

vec3 getNormal(vec3 p) {
    Material m;
    float d = sceneSDF(p, m);
    vec2 e = vec2(0.001, 0.0);
    
    vec3 n = d - vec3(
        sceneSDF(p - e.xyy, m),
        sceneSDF(p - e.yxy, m),
        sceneSDF(p - e.yyx, m)
    );
    
    return normalize(n);
}

// ============ LIGHTING ============

vec3 getLight(vec3 p, vec3 rd, Material mat) {
    vec3 lightPos = vec3(5.0, 5.0, 5.0);
    vec3 lightDir = normalize(lightPos - p);
    vec3 normal = getNormal(p);
    
    // Diffuse
    float diff = max(dot(normal, lightDir), 0.0);
    
    // Specular
    vec3 reflectDir = reflect(-lightDir, normal);
    float spec = pow(max(dot(rd, reflectDir), 0.0), 32.0 * (1.0 - mat.roughness));
    
    // Fresnel
    float fresnel = pow(1.0 - max(dot(-rd, normal), 0.0), 3.0);
    
    // Ambient occlusion approximation
    float ao = 1.0;
    
    vec3 col = mat.albedo * diff * (1.0 - mat.metallic);
    col += vec3(1.0) * spec * mat.metallic;
    col += mat.albedo * fresnel * 0.2;
    col += mat.albedo * 0.05 * ao; // ambient
    
    // Emissive
    col += mat.albedo * mat.emissive;
    
    return col;
}

// ============ MAIN ============

void main() {
    vec2 uv = (gl_FragCoord.xy - 0.5 * uResolution) / uResolution.y;
    
    // Camera
    vec3 ro = uCameraPos;
    vec3 rd = normalize(uCameraMatrix * vec4(uv.x, uv.y, 1.0, 0.0)).xyz;
    
    Material mat;
    float d = rayMarch(ro, rd, mat);
    
    vec3 col = vec3(0.02, 0.02, 0.05); // background
    
    if (d < MAX_DIST) {
        vec3 p = ro + rd * d;
        col = getLight(p, rd, mat);
        
        // Fog
        col = mix(col, vec3(0.02, 0.02, 0.05), 1.0 - exp(-0.01 * d * d));
    }
    
    // Bloom approximation
    col += col * col * 0.3;
    
    // Tone mapping
    col = col / (1.0 + col);
    col = pow(col, vec3(0.4545));
    
    gl_FragColor = vec4(col, 1.0);
}
