export const FRACTAL2D_VERTEX = `
    precision highp float;
    attribute vec3 position;
    attribute vec2 uv;
    uniform mat4 worldViewProjection;
    varying vec2 vUV;
    void main() {
        gl_Position = worldViewProjection * vec4(position, 1.0);
        vUV = uv;
    }
`;

export const FRACTAL2D_FRAGMENT = `
    precision highp float;
    varying vec2 vUV;

    uniform vec2 resolution;
    uniform vec2 center;      // OffsetX, OffsetY
    uniform float zoom;
    uniform int maxIterations;
    uniform int algorithm;    // 0:Mandel, 1:Julia, 2:Ship, 3:Newton
    uniform int colorScheme;  // 0:BlueGold, 1:Greyscale, 2:Fire, 3:Rainbow
    uniform vec2 juliaC;

    vec3 hsv2rgb(vec3 c) {
        vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
        vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
        return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
    }

    // --- Color Schemes ---
    vec3 getColor(float t, int iter, int maxIter, int root) {
        if (iter >= maxIter) return vec3(0.0);

        // special newton coloring
        if (algorithm == 3) {
            float val = 1.0 - (float(iter) / 20.0); // Weicheres Shading für Newton
            val = clamp(val, 0.0, 1.0);
            if (root == 1) return vec3(val, 0.0, 0.0); // Rot
            if (root == 2) return vec3(0.0, val, 0.0); // Grün
            if (root == 3) return vec3(0.0, 0.0, val); // Blau
            return vec3(0.0);
        }

        // default color
        if (colorScheme == 0) { // Blue-Gold
            return vec3(
                9.0 * (1.0-t)*t*t*t,
                15.0 * (1.0-t)*(1.0-t)*t*t,
                8.5 * (1.0-t)*(1.0-t)*(1.0-t)*t
            ) * 3.0;
        }
        if (colorScheme == 1) { // Greyscale
            return vec3(t);
        }
        if (colorScheme == 2) { // Fire
            float f = sqrt(t);
            return vec3(f * 2.0, (f - 0.3) * 3.0, (f - 0.6) * 6.0);
        }
        if (colorScheme == 3) { // Rainbow
            return hsv2rgb(vec3(t * 5.0, 1.0, 1.0));
        }
        return vec3(t);
    }

    void main(void) {
        float aspect = resolution.x / resolution.y;
        vec2 uv = (vUV - 0.5) * vec2(aspect, 1.0);
        vec2 c = uv / zoom + center;

        vec2 z = c;
        // For Julia is c fix, z changes. For Mandel is z=0, c changes.
        if (algorithm == 1) {
            z = c;
            c = juliaC;
        } else if (algorithm != 3) {
             z = vec2(0.0);
        }

        int iter = 0;
        int root = 0;

        // --- Algorithms ---
        if (algorithm == 3) { // Newton: z^3 - 1
            z = c;
            for(int i=0; i<100; i++) {
                if (i >= maxIterations) break;

                // z^3 - 1
                // z_new = z - (z^3 - 1) / (3*z^2)
                // simplified: z_new = (2*z^3 + 1) / (3*z^2)

                float zx2 = z.x * z.x;
                float zy2 = z.y * z.y;
                float denom = 3.0 * (zx2 + zy2) * (zx2 + zy2); // |3z^2|^2 simplified

                // z -= (z^3-1)/(3z^2)

                vec2 z2 = vec2(z.x*z.x - z.y*z.y, 2.0*z.x*z.y);
                vec2 z3 = vec2(z2.x*z.x - z2.y*z.y, z2.x*z.y + z2.y*z.x);

                vec2 num = z3 - vec2(1.0, 0.0);
                vec2 den = 3.0 * z2;

                // Division Complex: (a+bi)/(c+di) = ((ac+bd) + (bc-ad)i) / (c^2+d^2)
                float d = den.x*den.x + den.y*den.y;
                if(d < 0.000001) { iter=maxIterations; break; }

                vec2 div = vec2(
                    (num.x*den.x + num.y*den.y)/d,
                    (num.y*den.x - num.x*den.y)/d
                );

                z -= div;
                iter++;

                // Roots check
                // 1. (1, 0)
                if (distance(z, vec2(1.0, 0.0)) < 0.001) { root = 1; break; }
                // 2. (-0.5, 0.866)
                if (distance(z, vec2(-0.5, 0.866)) < 0.001) { root = 2; break; }
                // 3. (-0.5, -0.866)
                if (distance(z, vec2(-0.5, -0.866)) < 0.001) { root = 3; break; }
            }
        }
        else { // Mandelbrot (0), Julia (1), Burning Ship (2)
            for(int i=0; i<2000; i++) {
                if (i >= maxIterations) break;

                float x2 = z.x * z.x;
                float y2 = z.y * z.y;

                if (x2 + y2 > 4.0) {
                    iter = i;
                    break;
                }
                iter = i;

                if (algorithm == 2) { // Burning Ship
                    z.y = abs(z.y);
                    z.x = abs(z.x);
                }

                // z = z^2 + c
                float nextX = x2 - y2 + c.x;
                z.y = 2.0 * z.x * z.y + c.y;
                z.x = nextX;
            }
        }

        float t = float(iter) / float(maxIterations);
        vec3 color = getColor(t, iter, maxIterations, root);
        gl_FragColor = vec4(color, 1.0);
    }
`;
