"use client";

import React, { useMemo, useRef } from "react";
import { useFrame } from "@react-three/fiber";
import * as THREE from "three";
import { C, BRAIN_Y, P } from "./theme";
import { clamp01, damp, lerp, seeded, smoothstep } from "./math";

type Props = {
  progress: React.RefObject<number>;
  reduced?: boolean;
  isMobile?: boolean;
};

/** Evenly distributed points on a unit sphere (Fibonacci spiral). */
function fibonacciSphere(n: number, radiusJitter = 0): Float32Array {
  const arr = new Float32Array(n * 3);
  const golden = Math.PI * (3 - Math.sqrt(5));
  for (let i = 0; i < n; i++) {
    const y = 1 - (i / (n - 1)) * 2;
    const r = Math.sqrt(1 - y * y);
    const theta = golden * i;
    const jitter = 1 + (seeded(i * 1.7) - 0.5) * radiusJitter;
    arr[i * 3] = Math.cos(theta) * r * jitter;
    arr[i * 3 + 1] = y * jitter;
    arr[i * 3 + 2] = Math.sin(theta) * r * jitter;
  }
  return arr;
}

/**
 * The central "Logistics Brain": a glowing icosahedral core wrapped in two
 * counter-rotating wireframe shells and surrounded by thousands of orbiting
 * particles. It births into the scene, breathes continuously, recedes slightly
 * for the eagle-eye network pass and pulses brighter for the finale.
 */
function Brain({ progress, isMobile = false }: Props) {
  const group = useRef<THREE.Group>(null);
  const coreA = useRef<THREE.Mesh>(null);
  const coreB = useRef<THREE.Mesh>(null);
  const haloRef = useRef<THREE.Mesh>(null);
  const haloMat = useRef<THREE.MeshBasicMaterial>(null);
  const shellPts = useRef<THREE.Points>(null);
  const orbitA = useRef<THREE.Points>(null);
  const orbitB = useRef<THREE.Points>(null);
  const eased = useRef(0);

  const shellCount = isMobile ? 700 : 1500;
  const orbitCount = isMobile ? 900 : 2200;

  const shellPos = useMemo(() => fibonacciSphere(shellCount, 0.18), [shellCount]);
  const orbitAPos = useMemo(() => fibonacciSphere(orbitCount, 0.55), [orbitCount]);
  const orbitBPos = useMemo(() => fibonacciSphere(Math.floor(orbitCount * 0.6), 0.7), [orbitCount]);

  useFrame((state, dt) => {
    const p = progress.current ?? 0;
    eased.current = damp(eased.current, p, 3, dt);
    const e = eased.current;
    const t = state.clock.elapsedTime;

    const g = group.current;
    if (!g) return;

    // Birth: scale up from nothing across the first beat.
    const birth = smoothstep(0, P.routes, e);
    // Recede a touch while the camera is overhead studying the network.
    const recede = smoothstep(P.network, P.network + 0.06, e) * (1 - smoothstep(P.ecosystem, P.finale, e));
    // Finale: swell + brighten as the whole system lights up.
    const finale = smoothstep(P.finale, 1, e);

    const breathe = 1 + Math.sin(t * 0.9) * 0.03;
    // Base factor keeps the "brain" small — it's a depot/control beacon over the
    // map centre now, not the hero object. The map + routes carry the story.
    const scale = 0.5 * lerp(0.001, 1, birth) * (1 - recede * 0.32) * (1 + finale * 0.18) * breathe;
    g.scale.setScalar(scale);
    g.position.y = BRAIN_Y + Math.sin(t * 0.6) * 0.18;
    g.rotation.y = t * 0.12;

    if (coreA.current) coreA.current.rotation.set(t * 0.18, t * 0.24, 0);
    if (coreB.current) coreB.current.rotation.set(-t * 0.22, t * 0.16, t * 0.1);
    if (shellPts.current) shellPts.current.rotation.y = t * 0.06;
    if (orbitA.current) {
      orbitA.current.rotation.y = t * 0.35;
      orbitA.current.rotation.x = Math.sin(t * 0.2) * 0.3;
    }
    if (orbitB.current) {
      orbitB.current.rotation.y = -t * 0.28;
      orbitB.current.rotation.z = t * 0.18;
    }

    if (haloRef.current) {
      const hs = 1 + Math.sin(t * 1.6) * 0.06 + finale * 0.4;
      haloRef.current.scale.setScalar(hs);
    }
    if (haloMat.current) {
      haloMat.current.opacity = clamp01(0.22 + Math.sin(t * 1.6) * 0.05 + finale * 0.25) * birth;
    }
  });

  return (
    <group ref={group} position={[0, BRAIN_Y, 0]}>
      {/* Soft inner glow */}
      <mesh>
        <sphereGeometry args={[0.95, 24, 24]} />
        <meshBasicMaterial color={C.blue} transparent opacity={0.18} blending={THREE.AdditiveBlending} depthWrite={false} />
      </mesh>

      {/* Bright core */}
      <mesh>
        <sphereGeometry args={[0.42, 24, 24]} />
        <meshBasicMaterial color={C.white} transparent opacity={0.9} blending={THREE.AdditiveBlending} depthWrite={false} />
      </mesh>

      {/* Counter-rotating wireframe shells = the "folds" of the brain */}
      <mesh ref={coreA}>
        <icosahedronGeometry args={[1.35, 1]} />
        <meshBasicMaterial color={C.cyan} wireframe transparent opacity={0.55} blending={THREE.AdditiveBlending} depthWrite={false} />
      </mesh>
      <mesh ref={coreB}>
        <icosahedronGeometry args={[1.7, 2]} />
        <meshBasicMaterial color={C.violet} wireframe transparent opacity={0.32} blending={THREE.AdditiveBlending} depthWrite={false} />
      </mesh>

      {/* Dense synapse points hugging the core */}
      <points ref={shellPts}>
        <bufferGeometry>
          <bufferAttribute attach="attributes-position" args={[shellPos, 3]} />
        </bufferGeometry>
        <pointsMaterial size={isMobile ? 0.05 : 0.045} color={C.sky} transparent opacity={0.85} sizeAttenuation blending={THREE.AdditiveBlending} depthWrite={false} />
      </points>

      {/* Two orbiting particle clouds (kept tight so they don't clutter the map) */}
      <points ref={orbitA} scale={1.6}>
        <bufferGeometry>
          <bufferAttribute attach="attributes-position" args={[orbitAPos, 3]} />
        </bufferGeometry>
        <pointsMaterial size={0.04} color={C.cyan} transparent opacity={0.6} sizeAttenuation blending={THREE.AdditiveBlending} depthWrite={false} />
      </points>
      <points ref={orbitB} scale={2.0}>
        <bufferGeometry>
          <bufferAttribute attach="attributes-position" args={[orbitBPos, 3]} />
        </bufferGeometry>
        <pointsMaterial size={0.035} color={C.purple} transparent opacity={0.45} sizeAttenuation blending={THREE.AdditiveBlending} depthWrite={false} />
      </points>

      {/* Pulsing halo ring */}
      <mesh ref={haloRef} rotation={[Math.PI / 2, 0, 0]}>
        <ringGeometry args={[2.1, 2.25, 64]} />
        <meshBasicMaterial ref={haloMat} color={C.cyan} transparent opacity={0.22} side={THREE.DoubleSide} blending={THREE.AdditiveBlending} depthWrite={false} />
      </mesh>
    </group>
  );
}

export default React.memo(Brain);
