import { useEffect, useRef } from "react";
import * as THREE from "three";

export function useCinematicCanvas(canvasRef: React.RefObject<HTMLCanvasElement | null>) {
  const frameRef = useRef<number>(0);

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;

    // ── Renderer ──────────────────────────────────────────────────────────────
    const renderer = new THREE.WebGLRenderer({ canvas, antialias: true, alpha: false });
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setClearColor(0x000000, 1);

    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 2000);
    camera.position.z = 5;

    // ── Star field (static background) ────────────────────────────────────────
    const starCount = 2000;
    const starPositions = new Float32Array(starCount * 3);
    for (let i = 0; i < starCount; i++) {
      starPositions[i * 3] = (Math.random() - 0.5) * 200;
      starPositions[i * 3 + 1] = (Math.random() - 0.5) * 200;
      starPositions[i * 3 + 2] = (Math.random() - 0.5) * 200;
    }
    const starGeo = new THREE.BufferGeometry();
    starGeo.setAttribute("position", new THREE.BufferAttribute(starPositions, 3));
    const starMat = new THREE.PointsMaterial({ color: 0xffffff, size: 0.12, sizeAttenuation: true, transparent: true, opacity: 0.55 });
    scene.add(new THREE.Points(starGeo, starMat));

    // ── Speed lines (diagonal streaks shooting across) ─────────────────────────
    const LINE_COUNT = 120;
    const lineGroup = new THREE.Group();
    scene.add(lineGroup);

    interface SpeedLine {
      mesh: THREE.Mesh;
      speed: number;
      resetX: number;
      resetY: number;
    }
    const lines: SpeedLine[] = [];

    for (let i = 0; i < LINE_COUNT; i++) {
      const length = 0.4 + Math.random() * 2.5;
      const geo = new THREE.PlaneGeometry(0.012, length);
      const mat = new THREE.MeshBasicMaterial({
        color: 0xffffff,
        transparent: true,
        opacity: 0.08 + Math.random() * 0.18,
      });
      const mesh = new THREE.Mesh(geo, mat);

      // Spread across a wide area
      const rx = (Math.random() - 0.5) * 30;
      const ry = (Math.random() - 0.5) * 20;
      const rz = -5 - Math.random() * 15;
      mesh.position.set(rx, ry, rz);
      // Tilt ~45° like 8bit.ai streaks
      mesh.rotation.z = Math.PI / 4 + (Math.random() - 0.5) * 0.3;

      lineGroup.add(mesh);
      lines.push({ mesh, speed: 0.04 + Math.random() * 0.12, resetX: rx, resetY: ry });
    }

    // ── North star compass particle cluster (centre glow) ─────────────────────
    const compassCount = 600;
    const compassPositions = new Float32Array(compassCount * 3);
    const compassColors = new Float32Array(compassCount * 3);
    const blueColor = new THREE.Color(0x3b82f6);
    const whiteColor = new THREE.Color(0xffffff);

    for (let i = 0; i < compassCount; i++) {
      // Distribute in a loose sphere
      const theta = Math.random() * Math.PI * 2;
      const phi = Math.acos(2 * Math.random() - 1);
      const r = 0.3 + Math.random() * 1.8;
      compassPositions[i * 3] = r * Math.sin(phi) * Math.cos(theta);
      compassPositions[i * 3 + 1] = r * Math.sin(phi) * Math.sin(theta);
      compassPositions[i * 3 + 2] = r * Math.cos(phi) - 2;

      const mix = Math.random();
      const c = blueColor.clone().lerp(whiteColor, mix);
      compassColors[i * 3] = c.r;
      compassColors[i * 3 + 1] = c.g;
      compassColors[i * 3 + 2] = c.b;
    }

    const compassGeo = new THREE.BufferGeometry();
    compassGeo.setAttribute("position", new THREE.BufferAttribute(compassPositions, 3));
    compassGeo.setAttribute("color", new THREE.BufferAttribute(compassColors, 3));
    const compassMat = new THREE.PointsMaterial({
      size: 0.04,
      vertexColors: true,
      transparent: true,
      opacity: 0.85,
      sizeAttenuation: true,
    });
    const compassPoints = new THREE.Points(compassGeo, compassMat);
    scene.add(compassPoints);

    // ── Ambient blue glow ring ─────────────────────────────────────────────────
    const ringGeo = new THREE.TorusGeometry(1.4, 0.006, 8, 120);
    const ringMat = new THREE.MeshBasicMaterial({ color: 0x3b82f6, transparent: true, opacity: 0.35 });
    const ring = new THREE.Mesh(ringGeo, ringMat);
    ring.position.z = -2;
    scene.add(ring);

    const ring2Geo = new THREE.TorusGeometry(2.1, 0.003, 8, 120);
    const ring2Mat = new THREE.MeshBasicMaterial({ color: 0x1d4ed8, transparent: true, opacity: 0.18 });
    const ring2 = new THREE.Mesh(ring2Geo, ring2Mat);
    ring2.position.z = -2;
    scene.add(ring2);

    // ── Animation loop ─────────────────────────────────────────────────────────
    let t = 0;
    const animate = () => {
      frameRef.current = requestAnimationFrame(animate);
      t += 0.005;

      // Rotate compass particle cloud slowly
      compassPoints.rotation.y = t * 0.15;
      compassPoints.rotation.x = Math.sin(t * 0.1) * 0.08;

      // Pulse ring opacity
      (ring.material as THREE.MeshBasicMaterial).opacity = 0.2 + Math.sin(t * 1.2) * 0.12;
      (ring2.material as THREE.MeshBasicMaterial).opacity = 0.1 + Math.sin(t * 0.8 + 1) * 0.06;
      ring.rotation.z = t * 0.05;
      ring2.rotation.z = -t * 0.03;

      // Move speed lines diagonally (bottom-left to top-right)
      for (const ln of lines) {
        ln.mesh.position.x += ln.speed * 0.7;
        ln.mesh.position.y += ln.speed * 0.7;
        // Reset when off screen
        if (ln.mesh.position.x > 18 || ln.mesh.position.y > 14) {
          ln.mesh.position.x = ln.resetX - 20;
          ln.mesh.position.y = ln.resetY - 15;
        }
      }

      // Subtle camera drift
      camera.position.x = Math.sin(t * 0.07) * 0.15;
      camera.position.y = Math.cos(t * 0.05) * 0.1;
      camera.lookAt(0, 0, -2);

      renderer.render(scene, camera);
    };
    animate();

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

    return () => {
      cancelAnimationFrame(frameRef.current);
      window.removeEventListener("resize", onResize);
      renderer.dispose();
    };
  }, [canvasRef]);
}
