// @ts-nocheck
import { useRef, useMemo, useEffect } from 'react';
import { Canvas, useFrame, useThree } from '@react-three/fiber';
import * as THREE from 'three';

const BOARD_SIZE = 200;
const GRID_DIVISIONS = 16;
const JUNCTION_SPACING = BOARD_SIZE / GRID_DIVISIONS;
const HALF_BOARD = BOARD_SIZE / 2;
const ORB_COUNT = 20;
const PULSE_COUNT = 10;

interface Junction {
  x: number;
  z: number;
  connections: number[];
}

interface Trace {
  start: number;
  end: number;
}

interface ParticleData {
  pos: THREE.Vector3;
  target: THREE.Vector3;
  junctionIndex: number;
  targetJunctionIndex: number;
  progress: number;
  speed: number;
  type: 'orb' | 'pulse';
}

function seededRandom(seed: number): () => number {
  let s = seed;
  return () => {
    s = (s * 9301 + 49297) % 233280;
    return s / 233280;
  };
}

function createGlowTexture(color: string): THREE.CanvasTexture {
  const canvas = document.createElement('canvas');
  canvas.width = 64;
  canvas.height = 64;
  const ctx = canvas.getContext('2d')!;

  const gradient = ctx.createRadialGradient(32, 32, 0, 32, 32, 32);
  gradient.addColorStop(0, color);
  gradient.addColorStop(0.3, color.replace(')', ', 0.8)').replace('rgb', 'rgba'));
  gradient.addColorStop(0.6, color.replace(')', ', 0.3)').replace('rgb', 'rgba'));
  gradient.addColorStop(1, 'rgba(0,0,0,0)');

  ctx.fillStyle = gradient;
  ctx.fillRect(0, 0, 64, 64);

  return new THREE.CanvasTexture(canvas);
}

function generateBoardData() {
  const rand = seededRandom(42);
  const junctions: Junction[] = [];
  const indexMap: Map<string, number> = new Map();

  for (let gx = 0; gx <= GRID_DIVISIONS; gx++) {
    for (let gz = 0; gz <= GRID_DIVISIONS; gz++) {
      const x = -HALF_BOARD + gx * JUNCTION_SPACING;
      const z = -HALF_BOARD + gz * JUNCTION_SPACING;
      const idx = junctions.length;
      junctions.push({ x, z, connections: [] });
      indexMap.set(`${gx},${gz}`, idx);
    }
  }

  for (let gx = 0; gx <= GRID_DIVISIONS; gx++) {
    for (let gz = 0; gz <= GRID_DIVISIONS; gz++) {
      const idx = indexMap.get(`${gx},${gz}`);
      if (idx === undefined) continue;

      if (gx < GRID_DIVISIONS) {
        const rightIdx = indexMap.get(`${gx + 1},${gz}`);
        if (rightIdx !== undefined) {
          junctions[idx].connections.push(rightIdx);
          junctions[rightIdx].connections.push(idx);
        }
      }

      if (gz < GRID_DIVISIONS) {
        const downIdx = indexMap.get(`${gx},${gz + 1}`);
        if (downIdx !== undefined) {
          junctions[idx].connections.push(downIdx);
          junctions[downIdx].connections.push(idx);
        }
      }

      if (gx < GRID_DIVISIONS && gz < GRID_DIVISIONS && rand() > 0.85) {
        const diagIdx = indexMap.get(`${gx + 1},${gz + 1}`);
        if (diagIdx !== undefined) {
          junctions[idx].connections.push(diagIdx);
          junctions[diagIdx].connections.push(idx);
        }
      }
    }
  }

  const traceSet = new Set<string>();
  const traces: Trace[] = [];
  for (const j of junctions) {
    const jIdx = junctions.indexOf(j);
    for (const c of j.connections) {
      const key = j.x < junctions[c].x || (j.x === junctions[c].x && j.z <= junctions[c].z)
        ? `${jIdx},${c}`
        : `${c},${jIdx}`;
      if (!traceSet.has(key)) {
        traceSet.add(key);
        traces.push({ start: jIdx, end: c });
      }
    }
  }

  const chips: Array<{ x: number; z: number; width: number; depth: number }> = [];
  const usedIndices = new Set<number>();
  for (let i = 0; i < 22; i++) {
    let attempts = 0;
    while (attempts < 50) {
      const idx = Math.floor(rand() * junctions.length);
      if (!usedIndices.has(idx) && junctions[idx].connections.length >= 2) {
        usedIndices.add(idx);
        chips.push({
          x: junctions[idx].x,
          z: junctions[idx].z,
          width: 5 + rand() * 7,
          depth: 5 + rand() * 7,
        });
        break;
      }
      attempts++;
    }
  }

  const capacitors: Array<{ x: number; z: number; radius: number; height: number }> = [];
  for (let i = 0; i < 45; i++) {
    const idx = Math.floor(rand() * junctions.length);
    capacitors.push({
      x: junctions[idx].x + (rand() - 0.5) * 3,
      z: junctions[idx].z + (rand() - 0.5) * 3,
      radius: 0.35 + rand() * 0.45,
      height: 1.2 + rand() * 2.2,
    });
  }

  const ics: Array<{ x: number; z: number; width: number; depth: number }> = [];
  const icCandidates = junctions.filter(j => j.connections.length > 2);
  for (let i = 0; i < Math.min(16, icCandidates.length); i++) {
    const j = icCandidates[i];
    ics.push({
      x: j.x,
      z: j.z,
      width: 10 + rand() * 6,
      depth: 6 + rand() * 4,
    });
  }

  return { junctions, traces, chips, capacitors, ics };
}

function TraceLines({ traces, junctions }: { traces: Trace[]; junctions: Junction[] }) {
  const geometry = useMemo(() => {
    const positions: number[] = [];
    for (const t of traces) {
      const start = junctions[t.start];
      const end = junctions[t.end];
      positions.push(start.x, 0.1, start.z);
      positions.push(end.x, 0.1, end.z);
    }
    const geo = new THREE.BufferGeometry();
    geo.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
    return geo;
  }, [traces, junctions]);

  return (
    <lineSegments geometry={geometry}>
      <lineBasicMaterial color="#3d5a3a" />
    </lineSegments>
  );
}

function Chips({ chips }: { chips: Array<{ x: number; z: number; width: number; depth: number }> }) {
  return (
    <group>
      {chips.map((chip, i) => (
        <group key={i} position={[chip.x, 0, chip.z]}>
          <mesh position={[0, 0.6, 0]} castShadow>
            <boxGeometry args={[chip.width, 1.2, chip.depth]} />
            <meshStandardMaterial color="#1c1c1c" roughness={0.4} metalness={0.5} />
          </mesh>
          <mesh position={[0, 1.25, 0]}>
            <boxGeometry args={[chip.width * 0.4, 0.25, chip.depth * 0.15]} />
            <meshStandardMaterial color="#3a3a3a" roughness={0.3} metalness={0.6} emissive="#0a1a0a" emissiveIntensity={0.2} />
          </mesh>
          {[-1, 1].map((side) =>
            Array.from({ length: Math.floor(chip.width / 1.2) }).map((_, pi) => (
              <mesh key={`pin-${side}-${pi}`} position={[side * (chip.width / 2 + 0.25), 0.25, -chip.depth / 2 + 1.0 + pi * 1.2]} castShadow>
                <boxGeometry args={[0.25, 0.5, 0.25]} />
                <meshStandardMaterial color="#909090" roughness={0.25} metalness={0.85} />
              </mesh>
            ))
          )}
          {[-1, 1].map((side) =>
            Array.from({ length: Math.floor(chip.depth / 1.2) }).map((_, pi) => (
              <mesh key={`pin-z-${side}-${pi}`} position={[-chip.width / 2 + 1.0 + pi * 1.2, 0.25, side * (chip.depth / 2 + 0.25)]} castShadow>
                <boxGeometry args={[0.25, 0.5, 0.25]} />
                <meshStandardMaterial color="#909090" roughness={0.25} metalness={0.85} />
              </mesh>
            ))
          )}
        </group>
      ))}
    </group>
  );
}

function Capacitors({ capacitors }: { capacitors: Array<{ x: number; z: number; radius: number; height: number }> }) {
  return (
    <group>
      {capacitors.map((cap, i) => (
        <mesh key={i} position={[cap.x, cap.height / 2, cap.z]} castShadow>
          <cylinderGeometry args={[cap.radius, cap.radius, cap.height, 8]} />
          <meshStandardMaterial color="#2d2d2d" roughness={0.35} metalness={0.5} />
        </mesh>
      ))}
    </group>
  );
}

function ICs({ ics }: { ics: Array<{ x: number; z: number; width: number; depth: number }> }) {
  return (
    <group>
      {ics.map((ic, i) => (
        <group key={i} position={[ic.x, 0, ic.z]}>
          <mesh position={[0, 0.8, 0]} castShadow>
            <boxGeometry args={[ic.width, 1.6, ic.depth]} />
            <meshStandardMaterial color="#181818" roughness={0.5} metalness={0.3} />
          </mesh>
          <mesh position={[0, 1.65, 0]}>
            <boxGeometry args={[ic.width * 0.2, 0.15, ic.depth * 0.1]} />
            <meshStandardMaterial color="#2a2a2a" roughness={0.4} metalness={0.5} />
          </mesh>
        </group>
      ))}
    </group>
  );
}

function ParticleSystem({ junctions }: { junctions: Junction[] }) {
  const orbRefs = useRef<(THREE.Mesh | null)[]>([]);
  const pulseRefs = useRef<(THREE.Mesh | null)[]>([]);
  const particles = useRef<ParticleData[]>([]);
  const initialized = useRef(false);
  const glowTexture = useMemo(() => createGlowTexture('rgb(0, 255, 68)'), []);
  const pulseGlowTexture = useMemo(() => createGlowTexture('rgb(0, 255, 255)'), []);

  useEffect(() => {
    if (initialized.current) return;
    initialized.current = true;

    const rand = seededRandom(Date.now());
    const initial: ParticleData[] = [];

    for (let i = 0; i < ORB_COUNT; i++) {
      const idx = Math.floor(rand() * junctions.length);
      const conn = junctions[idx].connections;
      const target = conn.length > 0 ? conn[Math.floor(rand() * conn.length)] : idx;
      initial.push({
        pos: new THREE.Vector3(junctions[idx].x, 0.4, junctions[idx].z),
        target: new THREE.Vector3(junctions[target].x, 0.4, junctions[target].z),
        junctionIndex: idx,
        targetJunctionIndex: target,
        progress: rand(),
        speed: 0.002 + rand() * 0.003,
        type: 'orb',
      });
    }

    for (let i = 0; i < PULSE_COUNT; i++) {
      const idx = Math.floor(rand() * junctions.length);
      const conn = junctions[idx].connections;
      const target = conn.length > 0 ? conn[Math.floor(rand() * conn.length)] : idx;
      initial.push({
        pos: new THREE.Vector3(junctions[idx].x, 0.4, junctions[idx].z),
        target: new THREE.Vector3(junctions[target].x, 0.4, junctions[target].z),
        junctionIndex: idx,
        targetJunctionIndex: target,
        progress: rand(),
        speed: 0.01 + rand() * 0.015,
        type: 'pulse',
      });
    }

    particles.current = initial;
  }, [junctions]);

  useFrame(() => {
    const p = particles.current;
    if (!p.length) return;

    for (let i = 0; i < p.length; i++) {
      const particle = p[i];
      particle.progress += particle.speed;

      if (particle.progress >= 1) {
        const conn = junctions[particle.junctionIndex].connections;
        if (conn.length > 0) {
          particle.junctionIndex = particle.targetJunctionIndex;
          const nextConn = junctions[particle.targetJunctionIndex].connections.filter(c => c !== particle.junctionIndex);
          particle.targetJunctionIndex = nextConn.length > 0
            ? nextConn[Math.floor(Math.random() * nextConn.length)]
            : conn[Math.floor(Math.random() * conn.length)];
          particle.progress = 0;
          particle.target.set(
            junctions[particle.targetJunctionIndex].x,
            0.4,
            junctions[particle.targetJunctionIndex].z
          );
        } else {
          particle.progress = 0;
        }
      }

      const startJ = junctions[particle.junctionIndex];
      particle.pos.x = startJ.x + (particle.target.x - startJ.x) * particle.progress;
      particle.pos.z = startJ.z + (particle.target.z - startJ.z) * particle.progress;
      particle.pos.y = 0.4 + Math.sin(particle.progress * Math.PI) * 0.6;

      if (particle.type === 'orb') {
        const mesh = orbRefs.current[i];
        if (mesh) {
          mesh.position.copy(particle.pos);
        }
      } else {
        const mesh = pulseRefs.current[i - ORB_COUNT];
        if (mesh) {
          mesh.position.copy(particle.pos);
          const scale = 1 - Math.abs(particle.progress - 0.5) * 2;
          mesh.scale.setScalar(0.4 + scale * 0.6);
          (mesh.material as THREE.MeshStandardMaterial).emissiveIntensity = 2 + scale * 4;
        }
      }
    }
  });

  return (
    <group>
      {Array.from({ length: ORB_COUNT }).map((_, i) => (
        <mesh
          key={`orb-${i}`}
          ref={(el) => { orbRefs.current[i] = el; }}
        >
          <planeGeometry args={[1.2, 1.2]} />
          <meshBasicMaterial
            map={glowTexture}
            transparent
            opacity={0.95}
            depthWrite={false}
            blending={THREE.AdditiveBlending}
          />
        </mesh>
      ))}
      {Array.from({ length: PULSE_COUNT }).map((_, i) => (
        <mesh
          key={`pulse-${i}`}
          ref={(el) => { pulseRefs.current[i] = el; }}
          rotation={[-Math.PI / 2, 0, 0]}
        >
          <planeGeometry args={[0.8, 0.8]} />
          <meshBasicMaterial
            map={pulseGlowTexture}
            transparent
            opacity={0.95}
            depthWrite={false}
            blending={THREE.AdditiveBlending}
          />
        </mesh>
      ))}
    </group>
  );
}

function CameraDrift() {
  const { camera } = useThree();
  const timeRef = useRef(0);

  useFrame((_, delta) => {
    timeRef.current += delta;
    const t = timeRef.current;

    camera.position.x = Math.sin(t * 0.05) * 3;
    camera.position.y = 80 + Math.sin(t * 0.07) * 2.5;
    camera.position.z = Math.cos(t * 0.04) * 5;

    camera.lookAt(0, 0, 0);
  });

  return null;
}

function Scene() {
  const boardData = useMemo(() => generateBoardData(), []);

  return (
    <>
      <ambientLight intensity={0.3} />
      <directionalLight position={[60, 120, 60]} intensity={0.7} castShadow />
      <directionalLight position={[-40, 80, -40]} intensity={0.4} />
      <pointLight position={[0, 40, 0]} intensity={0.6} color="#00ff44" distance={120} />

      <mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, -0.5, 0]} receiveShadow>
        <planeGeometry args={[BOARD_SIZE, BOARD_SIZE]} />
        <meshStandardMaterial color="#080808" roughness={0.85} metalness={0.15} />
      </mesh>

      <TraceLines traces={boardData.traces} junctions={boardData.junctions} />
      <Chips chips={boardData.chips} />
      <Capacitors capacitors={boardData.capacitors} />
      <ICs ics={boardData.ics} />
      <ParticleSystem junctions={boardData.junctions} />
      <CameraDrift />
    </>
  );
}

export default function GadgetGrid() {
  return (
    <div className="absolute inset-0">
      <Canvas
        camera={{ position: [0, 80, 0], fov: 45, near: 0.1, far: 500 }}
        gl={{ antialias: true, alpha: true }}
        dpr={[1, 1.5]}
      >
        <Scene />
      </Canvas>
    </div>
  );
}