"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import { Canvas, useFrame } from "@react-three/fiber";
import * as THREE from "three";

/**
 * The signature hero scene: a digital loom — a field of ~2,650 diamond
 * threads undulating like cloth. Azure and cyan rows follow an alternating
 * band pattern over deep navy, echoing the Vira.sa brand world.
 */

const COLS = 78;
const ROWS = 34;
const COUNT = COLS * ROWS;
const SPACING = 0.62;

const AZURE = new THREE.Color("#2E8BF7");
const CYAN = new THREE.Color("#4FC3FF");
const ICE = new THREE.Color("#8FC0F5");
const NAVY = new THREE.Color("#10305E");

function bandColor(row: number, col: number): THREE.Color {
  // band rhythm: navy ground, azure body rows, cyan highlight, ice accent row
  const m = row % 9;
  if (m === 4) return ICE;
  if (m === 3 || m === 5) return (col + row) % 2 ? ICE.clone().lerp(NAVY, 0.55) : NAVY;
  if (m === 0) return CYAN.clone().lerp(NAVY, 0.3);
  return (col + row) % 3 ? NAVY : AZURE.clone().lerp(NAVY, 0.25);
}

function Field({ paused }: { paused: boolean }) {
  const mesh = useRef<THREE.InstancedMesh>(null);
  const dummy = useMemo(() => new THREE.Object3D(), []);
  const pointer = useRef({ x: 0, y: 0 });

  const colors = useMemo(() => {
    const arr = new Float32Array(COUNT * 3);
    for (let r = 0; r < ROWS; r++) {
      for (let c = 0; c < COLS; c++) {
        const col = bandColor(r, c);
        col.toArray(arr, (r * COLS + c) * 3);
      }
    }
    return arr;
  }, []);

  useEffect(() => {
    const onMove = (e: PointerEvent) => {
      pointer.current.x = (e.clientX / window.innerWidth) * 2 - 1;
      pointer.current.y = (e.clientY / window.innerHeight) * 2 - 1;
    };
    window.addEventListener("pointermove", onMove, { passive: true });
    return () => window.removeEventListener("pointermove", onMove);
  }, []);

  useFrame((state) => {
    const m = mesh.current;
    if (!m || paused) return;
    const t = state.clock.elapsedTime;
    let i = 0;
    for (let r = 0; r < ROWS; r++) {
      for (let c = 0; c < COLS; c++) {
        const x = (c - COLS / 2) * SPACING;
        const z = (r - ROWS / 2) * SPACING;
        // cloth-like undulation: two crossing waves + a slow travelling swell
        const y =
          Math.sin(x * 0.55 + t * 0.9) * 0.34 +
          Math.cos(z * 0.7 + t * 0.6) * 0.26 +
          Math.sin((x + z) * 0.28 - t * 0.45) * 0.3;
        dummy.position.set(x, y, z);
        dummy.rotation.set(Math.PI / 2, 0, Math.PI / 4);
        const s = 1 + Math.sin(x * 0.5 + z * 0.4 + t) * 0.12;
        dummy.scale.set(s, s, 1);
        dummy.updateMatrix();
        m.setMatrixAt(i++, dummy.matrix);
      }
    }
    m.instanceMatrix.needsUpdate = true;

    // gentle mouse parallax on the whole loom
    const g = m.parent;
    if (g) {
      g.rotation.y += (pointer.current.x * 0.08 - g.rotation.y) * 0.04;
      g.rotation.x += (-0.52 + pointer.current.y * 0.04 - g.rotation.x) * 0.04;
    }
  });

  return (
    <group rotation={[-0.52, 0, 0]} position={[0, -1.1, 0]}>
      <instancedMesh ref={mesh} args={[undefined, undefined, COUNT]} frustumCulled={false}>
        <planeGeometry args={[0.34, 0.34]}>
          <instancedBufferAttribute attach="attributes-color" args={[colors, 3]} />
        </planeGeometry>
        <meshBasicMaterial vertexColors side={THREE.DoubleSide} toneMapped={false} />
      </instancedMesh>
    </group>
  );
}

export default function WovenField({ className }: { className?: string }) {
  const wrap = useRef<HTMLDivElement>(null);
  const [visible, setVisible] = useState(true);
  const [reduced, setReduced] = useState(false);
  const [hidden, setHidden] = useState(false);

  useEffect(() => {
    setReduced(window.matchMedia("(prefers-reduced-motion: reduce)").matches);
    const el = wrap.current;
    if (!el) return;
    const io = new IntersectionObserver(([e]) => setVisible(e.isIntersecting), { threshold: 0 });
    io.observe(el);
    const onVis = () => setHidden(document.hidden);
    document.addEventListener("visibilitychange", onVis);
    return () => {
      io.disconnect();
      document.removeEventListener("visibilitychange", onVis);
    };
  }, []);

  const paused = reduced || !visible || hidden;

  return (
    <div ref={wrap} className={`pointer-events-none ${className ?? ""}`} aria-hidden="true">
      <Canvas
        camera={{ position: [0, 3.6, 9.5], fov: 42 }}
        dpr={[1, 1.75]}
        gl={{ antialias: true, alpha: true, powerPreference: "high-performance" }}
        frameloop={paused ? "demand" : "always"}
        style={{ pointerEvents: "none" }}
      >
        <fog attach="fog" args={["#030D1F", 8, 22]} />
        <Field paused={paused} />
      </Canvas>
    </div>
  );
}
