/* eslint-disable */
/* STL viewer with hotspots. Uses THREE (loaded via UMD globals) */
const { useEffect, useRef, useState, useCallback } = React;

function STLViewer({ part, onLoaded, autoRotate = true, showHotspots = true, finishOverride = null, accentColor = null }) {
  const containerRef = useRef(null);
  const sceneRef = useRef({});
  const [hotspotPositions, setHotspotPositions] = useState([]);
  const [activeHotspot, setActiveHotspot] = useState(null);
  const [loading, setLoading] = useState(true);
  const [autoRotState, setAutoRotState] = useState(autoRotate);

  useEffect(() => { setAutoRotState(autoRotate); }, [autoRotate]);

  useEffect(() => {
    const container = containerRef.current;
    if (!container || !window.THREE) return;
    setLoading(true);
    setActiveHotspot(null);

    const THREE = window.THREE;
    const width = container.clientWidth;
    const height = container.clientHeight;

    // Scene
    const scene = new THREE.Scene();
    scene.background = null; // transparent — the stage CSS provides the background

    // Camera
    const camera = new THREE.PerspectiveCamera(35, width / height, 0.1, 100);
    camera.position.set(3.2, 2.2, 3.4);

    // Renderer
    const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
    renderer.setSize(width, height);
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    if ("outputColorSpace" in renderer && THREE.SRGBColorSpace) renderer.outputColorSpace = THREE.SRGBColorSpace;
    else if (THREE.sRGBEncoding) renderer.outputEncoding = THREE.sRGBEncoding;
    renderer.toneMapping = THREE.ACESFilmicToneMapping;
    renderer.toneMappingExposure = 1.05;
    container.appendChild(renderer.domElement);

    // Lights — editorial studio: 3-point with a warm key
    const ambient = new THREE.AmbientLight(0xfff5e0, 0.5);
    scene.add(ambient);

    const key = new THREE.DirectionalLight(0xffeac4, 1.5);
    key.position.set(4, 6, 4);
    scene.add(key);

    const fill = new THREE.DirectionalLight(0xd4d8ff, 0.6);
    fill.position.set(-4, 2, 2);
    scene.add(fill);

    const rim = new THREE.DirectionalLight(0xffffff, 0.8);
    rim.position.set(-2, 4, -5);
    scene.add(rim);

    const ground = new THREE.HemisphereLight(0xfff5e0, 0x2a2418, 0.4);
    scene.add(ground);

    // Controls
    const controls = new THREE.OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;
    controls.dampingFactor = 0.06;
    controls.enablePan = false;
    controls.minDistance = 2.4;
    controls.maxDistance = 8;
    controls.autoRotate = autoRotState;
    controls.autoRotateSpeed = 1.0;

    sceneRef.current = { THREE, scene, camera, renderer, controls, mesh: null };

    // Determine material from finish
    const finish = finishOverride || part.finish || "metal";
    const baseColor = accentColor ? new THREE.Color(accentColor) : new THREE.Color(part.color || "#888888");
    let material;
    if (finish === "metal") {
      material = new THREE.MeshPhysicalMaterial({
        color: baseColor,
        metalness: 0.85,
        roughness: 0.32,
        clearcoat: 0.2,
      });
    } else if (finish === "polished") {
      material = new THREE.MeshPhysicalMaterial({
        color: baseColor,
        metalness: 0.95,
        roughness: 0.12,
        clearcoat: 0.7,
        clearcoatRoughness: 0.1,
      });
    } else if (finish === "satin") {
      material = new THREE.MeshPhysicalMaterial({
        color: baseColor,
        metalness: 0.55,
        roughness: 0.55,
      });
    } else if (finish === "matte") {
      material = new THREE.MeshStandardMaterial({
        color: baseColor,
        metalness: 0.05,
        roughness: 0.85,
      });
    } else if (finish === "fabric") {
      material = new THREE.MeshStandardMaterial({
        color: baseColor,
        metalness: 0.0,
        roughness: 0.95,
      });
    } else if (finish === "fluid") {
      material = new THREE.MeshPhysicalMaterial({
        color: baseColor,
        metalness: 0.1,
        roughness: 0.05,
        transmission: 0.6,
        thickness: 0.5,
        ior: 1.4,
        clearcoat: 0.6,
      });
    } else {
      material = new THREE.MeshStandardMaterial({ color: baseColor, roughness: 0.6, metalness: 0.4 });
    }

    // Load STL
    const loader = new THREE.STLLoader();
    loader.load(
      part.model,
      (geometry) => {
        geometry.computeVertexNormals();
        // Center & scale to a 2-unit bounding box
        geometry.computeBoundingBox();
        const bb = geometry.boundingBox;
        const size = new THREE.Vector3();
        bb.getSize(size);
        const center = new THREE.Vector3();
        bb.getCenter(center);
        geometry.translate(-center.x, -center.y, -center.z);
        const maxDim = Math.max(size.x, size.y, size.z);
        const scale = 2 / maxDim;
        geometry.scale(scale, scale, scale);

        const mesh = new THREE.Mesh(geometry, material);
        scene.add(mesh);
        sceneRef.current.mesh = mesh;
        setLoading(false);
        if (onLoaded) onLoaded();
      },
      undefined,
      (err) => {
        console.error("STL load error:", err);
        setLoading(false);
      }
    );

    // Resize handling
    const handleResize = () => {
      if (!container) return;
      const w = container.clientWidth;
      const h = container.clientHeight;
      renderer.setSize(w, h);
      camera.aspect = w / h;
      camera.updateProjectionMatrix();
    };
    const ro = new ResizeObserver(handleResize);
    ro.observe(container);

    // Animation loop
    let rafId;
    const tick = () => {
      controls.autoRotate = sceneRef.current.autoRotate ?? autoRotState;
      controls.update();
      renderer.render(scene, camera);

      // Project hotspots
      if (part.hotspots && part.hotspots.length) {
        const mesh = sceneRef.current.mesh;
        if (mesh) {
          const w = container.clientWidth;
          const h = container.clientHeight;
          const positions = part.hotspots.map((hs) => {
            const v = new THREE.Vector3(hs.pos[0], hs.pos[1], hs.pos[2]);
            mesh.localToWorld(v);
            const world = v.clone();
            v.project(camera);
            const x = (v.x * 0.5 + 0.5) * w;
            const y = (-v.y * 0.5 + 0.5) * h;
            // Is the hotspot facing the camera? Check z > 1 means behind
            const behind = v.z > 1;
            // Distance to camera for depth-fade
            const camDist = world.distanceTo(camera.position);
            return { ...hs, x, y, behind, camDist };
          });
          setHotspotPositions(positions);
        }
      }
      rafId = requestAnimationFrame(tick);
    };
    tick();

    // Stop autorotate on user interaction
    const stopAuto = () => {
      sceneRef.current.autoRotate = false;
      setAutoRotState(false);
    };
    controls.addEventListener("start", stopAuto);

    return () => {
      cancelAnimationFrame(rafId);
      ro.disconnect();
      controls.dispose();
      renderer.dispose();
      if (renderer.domElement && renderer.domElement.parentNode) {
        renderer.domElement.parentNode.removeChild(renderer.domElement);
      }
      scene.traverse((obj) => {
        if (obj.geometry) obj.geometry.dispose();
        if (obj.material) {
          if (Array.isArray(obj.material)) obj.material.forEach((m) => m.dispose());
          else obj.material.dispose();
        }
      });
    };
  }, [part.id, part.model, finishOverride, accentColor]);

  // Expose controls
  const handleReset = useCallback(() => {
    const s = sceneRef.current;
    if (!s.controls || !s.camera) return;
    s.controls.reset();
    s.camera.position.set(3.2, 2.2, 3.4);
    s.controls.update();
  }, []);

  const toggleAutoRotate = useCallback(() => {
    setAutoRotState((v) => {
      const next = !v;
      if (sceneRef.current) sceneRef.current.autoRotate = next;
      return next;
    });
  }, []);

  return (
    <>
      <div ref={containerRef} style={{ position: "absolute", inset: 0 }} />
      {loading && (
        <div style={{
          position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center",
          fontFamily: "var(--serif)", fontStyle: "italic", fontSize: 18, color: "var(--muted)", zIndex: 4,
        }}>Loading model…</div>
      )}

      {/* Hotspots */}
      {showHotspots && hotspotPositions.map((hs) => (
        <div
          key={hs.id}
          className={"hotspot" + (activeHotspot === hs.id ? " on" : "")}
          style={{
            left: hs.x,
            top: hs.y,
            opacity: hs.behind ? 0.18 : 1,
            transition: "opacity 0.2s",
          }}
          onClick={(e) => {
            e.stopPropagation();
            setActiveHotspot(activeHotspot === hs.id ? null : hs.id);
            // Pause autorotate when an annotation is open
            if (sceneRef.current && activeHotspot !== hs.id) {
              sceneRef.current.autoRotate = false;
              setAutoRotState(false);
            }
          }}
        >
          <div className="hotspot-dot">{hs.id}</div>
          <div className="hotspot-card">
            <h5>{hs.label}</h5>
            <p>{hs.text}</p>
          </div>
        </div>
      ))}

      {/* Toolbar */}
      <div className="viewer-toolbar">
        <div className="viewer-help">Drag to rotate · Scroll to zoom</div>
        <div className="viewer-controls">
          <button className={"viewer-btn" + (autoRotState ? " on" : "")} onClick={toggleAutoRotate} title="Auto-rotate">
            <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.4"><path d="M2.5 8a5.5 5.5 0 0 1 9.5-3.8L13.5 3v3.5H10" strokeLinecap="round"/><path d="M13.5 8a5.5 5.5 0 0 1-9.5 3.8L2.5 13v-3.5H6" strokeLinecap="round"/></svg>
          </button>
          <button className="viewer-btn" onClick={handleReset} title="Reset view">
            <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.4"><circle cx="8" cy="8" r="5.5"/><circle cx="8" cy="8" r="1.5" fill="currentColor"/></svg>
          </button>
        </div>
      </div>

      {/* Live tag */}
      <div className="viewer-tag">
        <span className="live-dot" /> 3D · WebGL
      </div>
    </>
  );
}

window.STLViewer = STLViewer;
