// Three.js pastel companion — chubby satellite-blob hybrid with heart light
const { useEffect, useRef } = React;

function Companion({ size = 360 }) {
  const mountRef = useRef(null);
  const stateRef = useRef({ mx: 0, my: 0, wiggle: 0 });

  useEffect(() => {
    const mount = mountRef.current;
    if (!mount || !window.THREE) return;
    const THREE = window.THREE;

    const w = mount.clientWidth;
    const h = mount.clientHeight;

    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(40, w / h, 0.1, 100);
    camera.position.set(0, 0, 6);

    const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    renderer.setSize(w, h);
    renderer.setClearColor(0x000000, 0);
    mount.appendChild(renderer.domElement);

    // Lights — soft pastel rim setup, no harsh shadows
    const amb = new THREE.AmbientLight(0xfff0fb, 0.85);
    scene.add(amb);
    const key = new THREE.DirectionalLight(0xfbcfe8, 0.9); // pink key
    key.position.set(3, 4, 5);
    scene.add(key);
    const rim = new THREE.DirectionalLight(0xc4b5fd, 1.0); // lavender rim
    rim.position.set(-4, 2, -3);
    scene.add(rim);
    const warm = new THREE.PointLight(0xfed7aa, 0.7, 12); // peach warmth
    warm.position.set(-2, -1, 3);
    scene.add(warm);

    // Group for the companion
    const group = new THREE.Group();
    scene.add(group);

    // Body — chubby pastel blob (sphere with toon material)
    const bodyGeom = new THREE.SphereGeometry(1.15, 48, 36);
    // tone map for toon
    const grad = new Uint8Array([180, 200, 235, 255]);
    const tex = new THREE.DataTexture(grad, grad.length, 1, THREE.RedFormat);
    tex.needsUpdate = true;
    const bodyMat = new THREE.MeshToonMaterial({ color: 0xE9D5FF, gradientMap: tex });
    const body = new THREE.Mesh(bodyGeom, bodyMat);
    group.add(body);

    // Subtle pink cheek blushes (small flat ellipses)
    function makeCheek(x) {
      const g = new THREE.CircleGeometry(0.16, 24);
      const m = new THREE.MeshBasicMaterial({ color: 0xFBCFE8, transparent: true, opacity: 0.7 });
      const mesh = new THREE.Mesh(g, m);
      mesh.position.set(x, -0.05, 1.02);
      mesh.scale.set(1, 0.7, 1);
      return mesh;
    }
    group.add(makeCheek(-0.45));
    group.add(makeCheek(0.45));

    // Eyes — closed sleepy arcs (curve geometry with tube)
    function makeEye(x) {
      const curve = new THREE.CatmullRomCurve3([
        new THREE.Vector3(x - 0.13, 0.18, 1.04),
        new THREE.Vector3(x, 0.10, 1.10),
        new THREE.Vector3(x + 0.13, 0.18, 1.04),
      ]);
      const g = new THREE.TubeGeometry(curve, 16, 0.024, 8, false);
      const m = new THREE.MeshBasicMaterial({ color: 0x3B0764 });
      return new THREE.Mesh(g, m);
    }
    const eyeL = makeEye(-0.32);
    const eyeR = makeEye(0.32);
    group.add(eyeL); group.add(eyeR);

    // Tiny smile
    {
      const curve = new THREE.CatmullRomCurve3([
        new THREE.Vector3(-0.10, -0.18, 1.08),
        new THREE.Vector3(0, -0.24, 1.12),
        new THREE.Vector3(0.10, -0.18, 1.08),
      ]);
      const g = new THREE.TubeGeometry(curve, 16, 0.022, 8, false);
      const m = new THREE.MeshBasicMaterial({ color: 0x3B0764 });
      group.add(new THREE.Mesh(g, m));
    }

    // Antenna stem
    {
      const g = new THREE.CylinderGeometry(0.04, 0.04, 0.65, 12);
      const m = new THREE.MeshToonMaterial({ color: 0xC4B5FD, gradientMap: tex });
      const stem = new THREE.Mesh(g, m);
      stem.position.set(0, 1.45, 0);
      group.add(stem);
    }

    // Heart-shaped antenna light (made from two spheres + cone, low-poly)
    const heart = new THREE.Group();
    const heartMat = new THREE.MeshBasicMaterial({ color: 0xFBCFE8 });
    const lobeGeom = new THREE.SphereGeometry(0.16, 20, 16);
    const lobeL = new THREE.Mesh(lobeGeom, heartMat); lobeL.position.set(-0.10, 0.06, 0);
    const lobeR = new THREE.Mesh(lobeGeom, heartMat); lobeR.position.set(0.10, 0.06, 0);
    const tipGeom = new THREE.ConeGeometry(0.22, 0.32, 24);
    const tip = new THREE.Mesh(tipGeom, heartMat); tip.rotation.x = Math.PI; tip.position.set(0, -0.13, 0);
    heart.add(lobeL); heart.add(lobeR); heart.add(tip);
    heart.position.set(0, 1.95, 0);
    // glow sprite
    const glowCanvas = document.createElement('canvas');
    glowCanvas.width = glowCanvas.height = 128;
    const gctx = glowCanvas.getContext('2d');
    const radial = gctx.createRadialGradient(64,64,4,64,64,64);
    radial.addColorStop(0, 'rgba(251,207,232,0.9)');
    radial.addColorStop(0.5, 'rgba(251,207,232,0.35)');
    radial.addColorStop(1, 'rgba(251,207,232,0)');
    gctx.fillStyle = radial; gctx.fillRect(0,0,128,128);
    const glowTex = new THREE.CanvasTexture(glowCanvas);
    const glowMat = new THREE.SpriteMaterial({ map: glowTex, transparent: true, depthWrite: false, blending: THREE.NormalBlending });
    const glow = new THREE.Sprite(glowMat);
    glow.scale.set(1.3, 1.3, 1);
    heart.add(glow);
    group.add(heart);

    // Saturn-style ring (tilted) — soft pastel
    {
      const g = new THREE.RingGeometry(1.55, 1.85, 64);
      const m = new THREE.MeshBasicMaterial({ color: 0xFED7AA, side: THREE.DoubleSide, transparent: true, opacity: 0.55 });
      const ring = new THREE.Mesh(g, m);
      ring.rotation.x = Math.PI / 2.2;
      ring.rotation.z = 0.3;
      group.add(ring);
    }

    // Tiny floating particles around companion
    const particles = new THREE.Group();
    const partMat = new THREE.MeshBasicMaterial({ color: 0xC4B5FD, transparent: true, opacity: 0.85 });
    const partGeom = new THREE.SphereGeometry(0.04, 8, 6);
    const partInfo = [];
    for (let i = 0; i < 14; i++) {
      const p = new THREE.Mesh(partGeom, partMat.clone());
      p.material.color.setHex([0xC4B5FD, 0xFBCFE8, 0xFED7AA, 0xBBF7D0][i % 4]);
      const r = 2.2 + Math.random() * 0.8;
      const theta = Math.random() * Math.PI * 2;
      const phi = Math.random() * Math.PI;
      p.position.set(r * Math.cos(theta), r * Math.cos(phi) * 0.6, r * Math.sin(theta));
      particles.add(p);
      partInfo.push({ baseY: p.position.y, phase: Math.random() * Math.PI * 2, speed: 0.4 + Math.random() * 0.6 });
    }
    scene.add(particles);

    // Mouse tracking (relative to mount)
    function onMove(e) {
      const rect = mount.getBoundingClientRect();
      const x = (e.clientX - rect.left) / rect.width - 0.5;
      const y = (e.clientY - rect.top) / rect.height - 0.5;
      stateRef.current.mx = x;
      stateRef.current.my = y;
    }
    window.addEventListener('mousemove', onMove);

    // Click to wiggle
    function onClick() {
      stateRef.current.wiggle = 1;
    }
    renderer.domElement.style.cursor = 'pointer';
    renderer.domElement.addEventListener('click', onClick);

    // Animate
    let t = 0;
    let rafId;
    function tick() {
      t += 0.016;
      const s = stateRef.current;

      // floating
      group.position.y = Math.sin(t * 1.4) * 0.18;
      // base rotation
      const targetRotY = s.mx * 0.6;
      const targetRotX = s.my * 0.4;
      group.rotation.y += (targetRotY - group.rotation.y) * 0.06 + Math.sin(t * 0.5) * 0.001;
      group.rotation.x += (targetRotX - group.rotation.x) * 0.06;
      group.rotation.z = Math.sin(t * 0.8) * 0.04;

      // wiggle bounce on click
      if (s.wiggle > 0) {
        s.wiggle -= 0.018;
        const w = Math.max(0, s.wiggle);
        const bounce = Math.sin(w * 28) * w * 0.25;
        group.scale.setScalar(1 + bounce);
        group.rotation.z += Math.sin(w * 30) * w * 0.4;
      } else {
        group.scale.lerp(new THREE.Vector3(1,1,1), 0.2);
      }

      // particles drift
      particles.rotation.y += 0.0025;
      partInfo.forEach((info, i) => {
        const p = particles.children[i];
        p.position.y = info.baseY + Math.sin(t * info.speed + info.phase) * 0.18;
      });

      // heart glow pulse
      const pulse = 1 + Math.sin(t * 2.4) * 0.08;
      glow.scale.set(1.3 * pulse, 1.3 * pulse, 1);

      renderer.render(scene, camera);
      rafId = requestAnimationFrame(tick);
    }
    tick();

    function onResize() {
      const nw = mount.clientWidth;
      const nh = mount.clientHeight;
      camera.aspect = nw / nh;
      camera.updateProjectionMatrix();
      renderer.setSize(nw, nh);
    }
    window.addEventListener('resize', onResize);

    return () => {
      cancelAnimationFrame(rafId);
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('resize', onResize);
      renderer.domElement.removeEventListener('click', onClick);
      mount.removeChild(renderer.domElement);
      renderer.dispose();
    };
  }, []);

  return (
    <div className="relative" style={{ width: size, height: size }}>
      <div ref={mountRef} style={{ width: '100%', height: '100%' }} />
      {/* tiny floating sparkle decor overlay */}
      <div className="float-spark" style={{ left: '8%', top: '20%' }}>✦</div>
      <div className="float-spark" style={{ left: '85%', top: '15%', animationDelay: '1.5s' }}>✦</div>
      <div className="float-spark" style={{ left: '90%', top: '70%', animationDelay: '3s' }}>✿</div>
      <div className="float-spark" style={{ left: '5%', top: '75%', animationDelay: '2s' }}>♡</div>
      <div className="float-spark" style={{ left: '50%', top: '90%', animationDelay: '4s' }}>✦</div>
    </div>
  );
}

window.Companion = Companion;
