import { useEffect, useMemo, useRef } from "react";
import * as THREE from "three";
import { DataNet } from "@sjs/sdk";

const CHANNEL = "demo.array.trail";

export function SceneSyncDemo({ apiKey, mount }: { apiKey: string; mount: HTMLDivElement }) {
  const clientRef = useRef<DataNet | null>(null);
  const meshes = useMemo(() => [] as THREE.Mesh[], []);

  useEffect(() => {
    const scene = new THREE.Scene();
    scene.background = new THREE.Color("#0b1118");
    const camera = new THREE.PerspectiveCamera(50, mount.clientWidth / mount.clientHeight, 0.1, 100);
    camera.position.z = 6;

    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(mount.clientWidth, mount.clientHeight);
    mount.appendChild(renderer.domElement);

    const light = new THREE.PointLight(0xffffff, 2);
    light.position.set(2, 3, 4);
    scene.add(light);

    for (let index = 0; index < 8; index += 1) {
      const mesh = new THREE.Mesh(
        new THREE.SphereGeometry(0.18, 18, 18),
        new THREE.MeshStandardMaterial({ color: 0xa9d8ff }),
      );
      mesh.position.x = index * 0.5 - 1.75;
      scene.add(mesh);
      meshes.push(mesh);
    }

    const client = new DataNet({
      apiKey,
      clientId: "three-scene-demo",
      deviceName: "three.js Scene Demo",
    });

    client.subscribe(CHANNEL, (data) => {
      const samples = Array.isArray((data as { samples?: unknown[] }).samples)
        ? ((data as { samples: number[] }).samples)
        : [];
      meshes.forEach((mesh, index) => {
        const value = typeof samples[index] === "number" ? samples[index] : 0;
        mesh.position.y = value * 2 - 1;
        mesh.scale.setScalar(0.8 + value * 0.8);
      });
    });

    void client.connect();
    clientRef.current = client;

    let frame = 0;
    const tick = () => {
      frame = requestAnimationFrame(tick);
      renderer.render(scene, camera);
    };
    tick();

    return () => {
      cancelAnimationFrame(frame);
      client.disconnect();
      renderer.dispose();
      mount.removeChild(renderer.domElement);
    };
  }, [apiKey, meshes, mount]);

  return null;
}
