const { useEffect, useRef } = React;

const ColorBends = (props) => {
  const mountRef = useRef(null);

  useEffect(() => {
    let animationFrameId;
    const scene = new THREE.Scene();
    const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0.1, 10);
    camera.position.z = 1;

    const renderer = new THREE.WebGLRenderer({ alpha: props.transparent || true, antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setPixelRatio(window.devicePixelRatio);
    mountRef.current.appendChild(renderer.domElement);

    const geometry = new THREE.PlaneGeometry(2, 2);

    const vertexShader = `
      varying vec2 vUv;
      void main() {
        vUv = uv;
        gl_Position = vec4(position, 1.0);
      }
    `;

    const fragmentShader = `
      uniform float u_time;
      uniform vec2 u_resolution;
      uniform vec2 u_mouse;
      
      uniform vec3 u_color;
      
      uniform float u_rotation;
      uniform float u_speed;
      uniform float u_scale;
      uniform float u_frequency;
      uniform float u_warpStrength;
      uniform float u_mouseInfluence;
      uniform float u_noise;
      uniform float u_iterations;
      uniform float u_intensity;
      uniform float u_bandWidth;
      
      varying vec2 vUv;

      // Noise functions
      vec3 permute(vec3 x) { return mod(((x*34.0)+1.0)*x, 289.0); }
      float snoise(vec2 v){
        const vec4 C = vec4(0.211324865405187, 0.366025403784439,
                 -0.577350269189626, 0.024390243902439);
        vec2 i  = floor(v + dot(v, C.yy) );
        vec2 x0 = v -   i + dot(i, C.xx);
        vec2 i1;
        i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
        vec4 x12 = x0.xyxy + C.xxzz;
        x12.xy -= i1;
        i = mod(i, 289.0);
        vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))
        + i.x + vec3(0.0, i1.x, 1.0 ));
        vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy),
          dot(x12.zw,x12.zw)), 0.0);
        m = m*m ;
        m = m*m ;
        vec3 x = 2.0 * fract(p * C.www) - 1.0;
        vec3 h = abs(x) - 0.5;
        vec3 ox = floor(x + 0.5);
        vec3 a0 = x - ox;
        m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
        vec3 g;
        g.x  = a0.x  * x0.x  + h.x  * x0.y;
        g.yz = a0.yz * x12.xz + h.yz * x12.yw;
        return 130.0 * dot(m, g);
      }
      
      mat2 rotate2d(float _angle){
          return mat2(cos(_angle),-sin(_angle),
                      sin(_angle),cos(_angle));
      }

      void main() {
        vec2 st = gl_FragCoord.xy / u_resolution.xy;
        st.x *= u_resolution.x / u_resolution.y;

        // Apply mouse influence
        vec2 mouse = u_mouse * vec2(u_resolution.x/u_resolution.y, 1.0);
        float mouseDist = distance(st, mouse);
        vec2 mouseEffect = (st - mouse) * smoothstep(0.5, 0.0, mouseDist) * u_mouseInfluence * 0.5;
        st += mouseEffect;

        // Apply scale & rotation
        vec2 pos = st * u_scale;
        pos = rotate2d(u_rotation) * pos;
        
        // Warping
        float n = 0.0;
        vec2 q = pos;
        float iter = u_iterations;
        
        for (float i = 1.0; i <= 5.0; i++) {
          if (i > iter) break;
          float t = u_time * u_speed;
          float angle = snoise(q * u_frequency + t) * 3.14159 * u_warpStrength;
          q += vec2(cos(angle), sin(angle)) * 0.1;
        }
        
        n = snoise(q * u_frequency);

        // Bands
        float bands = sin(n * u_bandWidth) * 0.5 + 0.5;
        
        // Intensity and Color
        float intensity = pow(bands, u_intensity);
        
        // Grain
        float random = fract(sin(dot(gl_FragCoord.xy, vec2(12.9898, 78.233))) * 43758.5453);
        intensity += (random - 0.5) * u_noise;

        // Final color
        vec3 finalColor = u_color; // Color remains solid cyan
        
        // Let the alpha control the visibility against the website's background
        float alpha = clamp(intensity, 0.0, 1.0);
        
        gl_FragColor = vec4(finalColor, alpha);
      }
    `;

    const uniforms = {
      u_time: { value: 0 },
      u_resolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
      u_mouse: { value: new THREE.Vector2(0.5, 0.5) },
      u_color: { value: new THREE.Color(props.colors?.[0] || "#00ceff") },
      u_rotation: { value: (props.rotation || 90) * (Math.PI / 180) },
      u_speed: { value: props.speed || 0.2 },
      u_scale: { value: props.scale || 1.0 },
      u_frequency: { value: props.frequency || 1.0 },
      u_warpStrength: { value: props.warpStrength || 1.0 },
      u_mouseInfluence: { value: props.mouseInfluence || 1.0 },
      u_noise: { value: props.noise || 0.15 },
      u_iterations: { value: props.iterations || 1.0 },
      u_intensity: { value: props.intensity || 1.5 },
      u_bandWidth: { value: props.bandWidth || 6.0 }
    };

    const material = new THREE.ShaderMaterial({
      vertexShader,
      fragmentShader,
      uniforms,
      transparent: true
    });

    const mesh = new THREE.Mesh(geometry, material);
    scene.add(mesh);

    const handleResize = () => {
      renderer.setSize(window.innerWidth, window.innerHeight);
      uniforms.u_resolution.value.set(window.innerWidth, window.innerHeight);
    };

    const handleMouseMove = (e) => {
      uniforms.u_mouse.value.set(
        e.clientX / window.innerWidth,
        1.0 - e.clientY / window.innerHeight
      );
    };

    window.addEventListener('resize', handleResize);
    window.addEventListener('mousemove', handleMouseMove);

    const render = () => {
      renderer.render(scene, camera);
    };
    render();

    return () => {
      window.removeEventListener('resize', handleResize);
      window.removeEventListener('mousemove', handleMouseMove);
      cancelAnimationFrame(animationFrameId);
      if (mountRef.current) {
        mountRef.current.removeChild(renderer.domElement);
      }
      geometry.dispose();
      material.dispose();
      renderer.dispose();
    };
  }, [props]);

  return <div ref={mountRef} style={{ width: '100%', height: '100%' }} />;
};

const App = () => {
  return (
    <div style={{ width: '100vw', height: '100vh', position: 'relative' }}>
      <ColorBends
        rotation={90}
        speed={0.2}
        colors={["#00ceff"]}
        transparent
        autoRotate={0}
        scale={1}
        frequency={1}
        warpStrength={1}
        mouseInfluence={1}
        parallax={0.5}
        noise={0.15}
        iterations={1}
        intensity={1.5}
        bandWidth={6}
      />
    </div>
  );
};

const root = ReactDOM.createRoot(document.getElementById('react-topography-root'));
root.render(<App />);
