/* ============ CHER — Three.js visuals (hero particles + Lightfall) ============ */
const { useEffect, useRef } = React;

const prefersReduced = () =>
  window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;

/* ---- observe visibility to pause RAF when offscreen ---- */
function useInViewRef(onChange){
  const ref = useRef(null);
  useEffect(()=>{
    if(!ref.current) return;
    const io = new IntersectionObserver(([e])=>onChange(e.isIntersecting),{threshold:0.01});
    io.observe(ref.current);
    return ()=>io.disconnect();
  },[]);
  return ref;
}

/* ================= GOLD HERO ================= */
function GoldHero(){
  const canvasRef = useRef(null);
  const visibleRef = useRef(true);
  const wrapRef = useInViewRef(v=>{ visibleRef.current = v; });

  useEffect(()=>{
    const canvas = canvasRef.current;
    if(!canvas || !window.THREE) return;
    const THREE = window.THREE;
    const reduced = prefersReduced();

    const scene = new THREE.Scene();
    scene.fog = new THREE.FogExp2(0x0b1d33, 0.0016);

    const camera = new THREE.PerspectiveCamera(62, innerWidth/innerHeight, 0.1, 2000);
    camera.position.set(0, 6, 230);

    const renderer = new THREE.WebGLRenderer({ canvas, antialias:true, alpha:true, powerPreference:'high-performance' });
    renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
    renderer.setSize(innerWidth, innerHeight);
    renderer.setClearColor(0x000000, 0);
    renderer.toneMapping = THREE.ACESFilmicToneMapping;
    renderer.toneMappingExposure = 0.9;

    // ---- gold particle field ----
    const palette = [
      new THREE.Color(0xE6C79A), new THREE.Color(0xC99A6B),
      new THREE.Color(0xE6C79A), new THREE.Color(0xd9b487),
      new THREE.Color(0xF7F5F0), new THREE.Color(0x9fb0b5)
    ];
    const groups = [];
    const layerConf = [
      { count: reduced?260:520, spread: 360, depth:-40, size:[1.2,3.2], speed:0.012 },
      { count: reduced?180:360, spread: 520, depth:-260, size:[2.0,5.0], speed:0.007 },
      { count: reduced?60:130,  spread: 300, depth: 80,  size:[3.0,7.5], speed:0.018 }
    ];
    layerConf.forEach((L,li)=>{
      const g = new THREE.BufferGeometry();
      const pos = new Float32Array(L.count*3);
      const col = new Float32Array(L.count*3);
      const siz = new Float32Array(L.count);
      const pha = new Float32Array(L.count);
      for(let i=0;i<L.count;i++){
        pos[i*3]   = (Math.random()-0.5)*L.spread*2;
        pos[i*3+1] = (Math.random()-0.5)*L.spread;
        pos[i*3+2] = L.depth + (Math.random()-0.5)*220;
        const c = palette[(Math.random()*palette.length)|0];
        col[i*3]=c.r; col[i*3+1]=c.g; col[i*3+2]=c.b;
        siz[i] = L.size[0] + Math.random()*(L.size[1]-L.size[0]);
        pha[i] = Math.random()*Math.PI*2;
      }
      g.setAttribute('position', new THREE.BufferAttribute(pos,3));
      g.setAttribute('pcolor', new THREE.BufferAttribute(col,3));
      g.setAttribute('psize', new THREE.BufferAttribute(siz,1));
      g.setAttribute('phase', new THREE.BufferAttribute(pha,1));
      const mat = new THREE.ShaderMaterial({
        uniforms:{ time:{value:0}, uScale:{value:renderer.getPixelRatio()} },
        vertexShader:`
          attribute vec3 pcolor; attribute float psize; attribute float phase;
          varying vec3 vColor; varying float vTw;
          uniform float time; uniform float uScale;
          void main(){
            vColor = pcolor;
            vTw = 0.55 + 0.45*sin(time*0.8 + phase);
            vec3 p = position;
            p.y += sin(time*0.12 + phase)*4.0;
            p.x += cos(time*0.08 + phase*1.3)*4.0;
            vec4 mv = modelViewMatrix * vec4(p,1.0);
            gl_PointSize = psize * uScale * (320.0 / -mv.z);
            gl_Position = projectionMatrix * mv;
          }`,
        fragmentShader:`
          varying vec3 vColor; varying float vTw;
          void main(){
            float d = length(gl_PointCoord - vec2(0.5));
            if(d>0.5) discard;
            float core = smoothstep(0.5,0.0,d);
            float halo = pow(core, 2.2);
            float a = halo * vTw;
            gl_FragColor = vec4(vColor, a);
          }`,
        transparent:true, blending:THREE.AdditiveBlending, depthWrite:false
      });
      const pts = new THREE.Points(g, mat);
      pts.userData.speed = L.speed;
      scene.add(pts);
      groups.push(pts);
    });

    // soft ambient glow planes (gold + teal bokeh)
    function glow(color, size, x,y,z, op){
      const cv = document.createElement('canvas'); cv.width=cv.height=128;
      const ctx = cv.getContext('2d');
      const gr = ctx.createRadialGradient(64,64,0,64,64,64);
      gr.addColorStop(0, color); gr.addColorStop(1, 'rgba(0,0,0,0)');
      ctx.fillStyle=gr; ctx.fillRect(0,0,128,128);
      const tex = new THREE.CanvasTexture(cv);
      const sp = new THREE.Sprite(new THREE.SpriteMaterial({map:tex, transparent:true, opacity:op, blending:THREE.AdditiveBlending, depthWrite:false}));
      sp.scale.set(size,size,1); sp.position.set(x,y,z); scene.add(sp); return sp;
    }
    glow('rgba(201,154,107,0.9)', 360, -160, 40, -120, 0.5);
    glow('rgba(21,65,74,0.9)', 460, 220, -60, -180, 0.55);
    glow('rgba(230,199,154,0.8)', 200, 120, 90, 30, 0.35);

    let raf, t=0;
    let mx=0, my=0, tmx=0, tmy=0;
    const onMove = e=>{ tmx=(e.clientX/innerWidth-0.5); tmy=(e.clientY/innerHeight-0.5); };
    window.addEventListener('pointermove', onMove);

    const clock = new THREE.Clock();
    function loop(){
      raf = requestAnimationFrame(loop);
      if(!visibleRef.current) return;
      const dt = Math.min(clock.getDelta(), 0.05);
      t += dt;
      mx += (tmx-mx)*0.04; my += (tmy-my)*0.04;
      groups.forEach((p,i)=>{
        p.material.uniforms.time.value = t;
        p.rotation.z += p.userData.speed*dt*0.5;
      });
      // gentle parallax camera
      camera.position.x += ((mx*36) - camera.position.x)*0.05 + Math.sin(t*0.1)*0.02;
      camera.position.y += ((6 - my*26) - camera.position.y)*0.05;
      camera.lookAt(0,4,-40);
      renderer.render(scene, camera);
    }
    loop();

    const onResize = ()=>{
      camera.aspect = innerWidth/innerHeight; camera.updateProjectionMatrix();
      renderer.setSize(innerWidth, innerHeight);
    };
    window.addEventListener('resize', onResize);

    return ()=>{
      cancelAnimationFrame(raf);
      window.removeEventListener('resize', onResize);
      window.removeEventListener('pointermove', onMove);
      groups.forEach(p=>{ p.geometry.dispose(); p.material.dispose(); });
      renderer.dispose();
    };
  },[]);

  return React.createElement('div', { ref:wrapRef, style:{position:'absolute',inset:0,zIndex:0} },
    React.createElement('canvas', { ref:canvasRef, id:'hero-canvas' })
  );
}

/* ================= LIGHTFALL (brand-tinted) ================= */
const LIGHTFALL_FRAG = `
precision highp float;
uniform vec3 iResolution; uniform vec2 iMouse; uniform float iTime;
uniform vec3 uC0; uniform vec3 uC1; uniform vec3 uC2;
uniform vec3 uBg; uniform float uSpeed; uniform float uOpacity;
varying vec2 vUv;
vec3 palette(float h){ if(h<0.34) return uC0; if(h<0.67) return uC1; return uC2; }
vec3 tanhv(vec3 x){ vec3 e=exp(-2.0*x); return (1.0-e)/(1.0+e); }
vec2 sceneC(vec2 frag, vec2 r){
  vec2 P=(frag+frag-r)/r.x; float z=0.0; float d=1e3; vec4 O=vec4(0.0);
  for(int k=0;k<34;k++){ if(d<=1e-4) break;
    O=z*normalize(vec4(P,3.0,0.0))-vec4(0.0,4.0,1.0,0.0)/4.5;
    d=1.0-sqrt(length(O*O)); z+=d; }
  return vec2(O.x, atan(O.z,O.y));
}
void main(){
  vec2 C=vUv*iResolution.xy; vec2 r=iResolution.xy;
  vec2 uv0=(C+C-r)/r.x;
  float T=0.1*iTime*uSpeed+9.0;
  float angRings=6.0; vec2 Y=vec2(5e-3,6.28318530718/angRings);
  vec2 c0=sceneC(C,r); vec2 cdx=sceneC(C+vec2(1.,0.),r); vec2 cdy=sceneC(C+vec2(0.,1.),r);
  vec2 dCx=cdx-c0; vec2 dCy=cdy-c0;
  dCx.y-=6.28318530718*floor(dCx.y/6.28318530718+0.5);
  dCy.y-=6.28318530718*floor(dCy.y/6.28318530718+0.5);
  vec2 fw=abs(dCx)+abs(dCy); C=c0;
  vec2 P=vec2(2.,1.)*uv0-(r/r.x)*vec2(0.,1.);
  vec4 O=vec4(uBg*70.0/(1e3*dot(P,P)+6.0),0.0);
  float zr=5e-4; vec2 rr=vec2(max(length(fw),1e-5)); float tail=19.0;
  for(int m=0;m<3;m++){
    float jf=float(m)+1.0;
    float ic=fract(sin(dot(vec2(jf,floor(C.x/Y.x+0.5)),vec2(7.,11.))*73.0));
    vec2 Pp=C-(T+T*ic)*vec2(0.,1.); Pp-=floor(Pp/Y+0.5)*Y;
    float h=fract(8663.0*ic); vec3 col=palette(h);
    float weight=mix(1.5,1.0+sin(T+7.0*h+4.0),1.0);
    vec2 inner=vec2(length(max(Pp,vec2(-1.,0.))),length(Pp)-zr)-zr;
    vec2 sm=vec2(1.0)-smoothstep(-rr,rr,inner);
    O.rgb+=dot(sm,vec2(exp(tail*Pp.y),3.0))*col*weight;
    C.x+=Y.x/8.0;
  }
  vec3 colr=sqrt(tanhv(max(O.rgb*0.85-vec3(0.04,0.08,0.02),0.0)));
  gl_FragColor=vec4(colr,uOpacity);
}`;

function hexToVec(THREE,h){ const c=new THREE.Color(h); return new THREE.Vector3(c.r,c.g,c.b); }

function Lightfall(){
  const canvasRef = useRef(null);
  const visibleRef = useRef(true);
  const wrapRef = useInViewRef(v=>{ visibleRef.current=v; });

  useEffect(()=>{
    const canvas = canvasRef.current;
    if(!canvas || !window.THREE) return;
    const THREE = window.THREE;
    const parent = canvas.parentElement;
    const renderer = new THREE.WebGLRenderer({ canvas, antialias:true, alpha:true });
    renderer.setPixelRatio(Math.min(devicePixelRatio,1.6));

    const scene = new THREE.Scene();
    const camera = new THREE.OrthographicCamera(-1,1,1,-1,0,1);
    const uniforms = {
      iResolution:{value:new THREE.Vector3(1,1,1)},
      iMouse:{value:new THREE.Vector2(0,0)},
      iTime:{value:0},
      uC0:{value:hexToVec(THREE,0xE6C79A)},
      uC1:{value:hexToVec(THREE,0xC99A6B)},
      uC2:{value:hexToVec(THREE,0x2c7a86)},
      uBg:{value:hexToVec(THREE,0x123a5c)},
      uSpeed:{value:0.5},
      uOpacity:{value:0.85}
    };
    const mat = new THREE.ShaderMaterial({
      uniforms,
      vertexShader:`varying vec2 vUv; void main(){ vUv=uv; gl_Position=vec4(position.xy,0.0,1.0); }`,
      fragmentShader:LIGHTFALL_FRAG, transparent:true
    });
    const quad = new THREE.Mesh(new THREE.PlaneGeometry(2,2), mat);
    scene.add(quad);

    function resize(){
      const w = parent.clientWidth, h = parent.clientHeight;
      renderer.setSize(w,h,false);
      const dpr = renderer.getPixelRatio();
      uniforms.iResolution.value.set(w*dpr, h*dpr, 1);
    }
    resize();
    const ro = new ResizeObserver(resize); ro.observe(parent);

    const onMove = e=>{ const rect=canvas.getBoundingClientRect(); uniforms.iMouse.value.set((e.clientX-rect.left)*renderer.getPixelRatio(),(rect.height-(e.clientY-rect.top))*renderer.getPixelRatio()); };
    parent.addEventListener('pointermove', onMove);

    let raf;
    const reduced = prefersReduced();
    function loop(t){
      raf = requestAnimationFrame(loop);
      if(!visibleRef.current) return;
      uniforms.iTime.value = reduced ? 6.0 : t*0.001;
      renderer.render(scene,camera);
      if(reduced){ cancelAnimationFrame(raf); }
    }
    raf = requestAnimationFrame(loop);

    return ()=>{ cancelAnimationFrame(raf); ro.disconnect(); parent.removeEventListener('pointermove',onMove); mat.dispose(); quad.geometry.dispose(); renderer.dispose(); };
  },[]);

  return React.createElement('div',{ref:wrapRef,style:{position:'absolute',inset:0,zIndex:0}},
    React.createElement('canvas',{ref:canvasRef,id:'lightfall-canvas'})
  );
}

window.GoldHero = GoldHero;
window.Lightfall = Lightfall;
window.prefersReduced = prefersReduced;
