import { Suspense, useMemo, useRef, useState, useEffect } from 'react'
import { Canvas, useFrame, useThree } from '@react-three/fiber'
import { OrbitControls, AdaptiveDpr } from '@react-three/drei'
import { EffectComposer, Bloom } from '@react-three/postprocessing'
import * as THREE from 'three'
import { useKnowledgeGraph } from '../../hooks/useBrainData'
import { useTransformedGraph, getTopNodes } from '../BrainGraph3D/GraphDataProvider'
import { useForceLayout } from '../BrainGraph3D/useForceLayout'
import { HERO_FORCE_PARAMS, HERO_NODE_COUNT, CAMERA, SCENE } from '../BrainGraph3D/constants'
import type { TransformedGraph, GraphNode3D, GraphEdge3D } from '../BrainGraph3D/types'
import NodeCloud from '../BrainGraph3D/NodeCloud'
import EdgeLines from '../BrainGraph3D/EdgeLines'
import NeuralPulse from '../BrainGraph3D/NeuralPulse'

// Synthetic graph for when API is unavailable
function generateSyntheticGraph(nodeCount: number): TransformedGraph {
  const types = ['lesson', 'failure', 'pattern', 'schema', 'evidence', 'decision']
  const nodes: GraphNode3D[] = Array.from({ length: nodeCount }, (_, i) => ({
    id: `syn_${i}`,
    label: `Node ${i}`,
    type: types[i % types.length],
    weight: 0.5 + Math.random() * 0.5,
    confidence: 0.3 + Math.random() * 0.7,
    degree: 0,
    radius: 0.15 + Math.random() * 0.25,
    colorIndex: i % types.length,
  }))

  const edges: GraphEdge3D[] = []
  for (let i = 0; i < nodeCount * 1.2; i++) {
    const s = Math.floor(Math.random() * nodeCount)
    let t = Math.floor(Math.random() * nodeCount)
    if (t === s) t = (t + 1) % nodeCount
    edges.push({ sourceIndex: s, targetIndex: t, type: 'related' })
    nodes[s].degree++
    nodes[t].degree++
  }

  return { nodes, edges }
}

const noop = () => {}

// Invisible interaction plane that tracks mouse position in 3D space
function MouseTracker({ mouseRef, clickingRef }: {
  mouseRef: React.MutableRefObject<THREE.Vector3>
  clickingRef: React.MutableRefObject<boolean>
}) {
  const { camera } = useThree()
  const planeRef = useRef<THREE.Mesh>(null!)

  // Keep plane facing camera
  useFrame(() => {
    if (planeRef.current) {
      planeRef.current.quaternion.copy(camera.quaternion)
    }
  })

  return (
    <mesh
      ref={planeRef}
      onPointerMove={(e) => {
        e.stopPropagation()
        mouseRef.current.copy(e.point)
      }}
      onPointerDown={(e) => {
        e.stopPropagation()
        clickingRef.current = true
      }}
      onPointerUp={() => { clickingRef.current = false }}
      onPointerLeave={() => {
        mouseRef.current.set(0, 0, 9999)
        clickingRef.current = false
      }}
    >
      <planeGeometry args={[300, 300]} />
      <meshBasicMaterial transparent opacity={0} side={THREE.DoubleSide} />
    </mesh>
  )
}

// Applies organic drift + mouse repulsion to settled positions
function InteractivePositions({ basePositions, interactivePos, mouseRef, clickingRef, nodeCount }: {
  basePositions: Float32Array
  interactivePos: Float32Array
  mouseRef: React.MutableRefObject<THREE.Vector3>
  clickingRef: React.MutableRefObject<boolean>
  nodeCount: number
}) {
  useFrame(({ clock }) => {
    const t = clock.getElapsedTime()
    const mx = mouseRef.current.x
    const my = mouseRef.current.y
    const mz = mouseRef.current.z
    const clicking = clickingRef.current

    for (let i = 0; i < nodeCount; i++) {
      // Base position from force layout
      let x = basePositions[i * 3]
      let y = basePositions[i * 3 + 1]
      let z = basePositions[i * 3 + 2]

      // Organic drift — each node sways like a living neuron
      const phase = i * 0.37
      x += Math.sin(t * 0.4 + phase) * 1.2
      y += Math.cos(t * 0.35 + phase * 1.3) * 1.2
      z += Math.sin(t * 0.25 + phase * 0.7) * 0.8

      // Mouse interaction — repulse on hover, explosion on click
      const dx = x - mx
      const dy = y - my
      const dz = z - mz
      const dist = Math.sqrt(dx * dx + dy * dy + dz * dz)

      if (dist < 30 && dist > 0.01) {
        const force = clicking ? 18 : 6
        const strength = (1 - dist / 30) * force
        const invDist = 1 / dist
        x += dx * invDist * strength
        y += dy * invDist * strength
        z += dz * invDist * strength
      }

      interactivePos[i * 3] = x
      interactivePos[i * 3 + 1] = y
      interactivePos[i * 3 + 2] = z
    }
  })

  return null
}

function HeroContent() {
  const { data: graphData } = useKnowledgeGraph()
  const fullGraph = useTransformedGraph(graphData)
  const syntheticGraph = useMemo(() => generateSyntheticGraph(HERO_NODE_COUNT), [])

  const heroGraph = useMemo(() => {
    if (fullGraph) return getTopNodes(fullGraph, HERO_NODE_COUNT)
    return syntheticGraph
  }, [fullGraph, syntheticGraph])

  const { positions } = useForceLayout(heroGraph, HERO_FORCE_PARAMS)

  // Interactive position buffers (mutated in-place each frame)
  const basePositions = useRef<Float32Array>(new Float32Array(0))
  const interactivePos = useRef<Float32Array>(new Float32Array(0))
  const mouseRef = useRef(new THREE.Vector3(0, 0, 9999))
  const clickingRef = useRef(false)
  const [ready, setReady] = useState(false)

  // Copy settled positions as base reference
  useEffect(() => {
    if (positions) {
      basePositions.current = new Float32Array(positions)
      if (interactivePos.current.length !== positions.length) {
        interactivePos.current = new Float32Array(positions)
      } else {
        interactivePos.current.set(positions)
      }
      if (!ready) setReady(true)
    }
  }, [positions, ready])

  if (!ready || !heroGraph) return null

  return (
    <>
      <MouseTracker mouseRef={mouseRef} clickingRef={clickingRef} />
      <InteractivePositions
        basePositions={basePositions.current}
        interactivePos={interactivePos.current}
        mouseRef={mouseRef}
        clickingRef={clickingRef}
        nodeCount={heroGraph.nodes.length}
      />
      <EdgeLines graph={heroGraph} positions={interactivePos.current} highlightSet={null} />
      <NodeCloud graph={heroGraph} positions={interactivePos.current} highlightSet={null} onHover={noop} onClick={noop} />
      <NeuralPulse graph={heroGraph} positions={interactivePos.current} />
    </>
  )
}

export default function BrainHero3D() {
  return (
    <div className="absolute inset-0">
      <Canvas
        camera={{ fov: CAMERA.fov, near: CAMERA.near, far: CAMERA.far, position: [0, 0, 60] }}
        gl={{ antialias: true, alpha: true, powerPreference: 'high-performance' }}
        onCreated={({ scene }) => {
          scene.background = new THREE.Color(SCENE.bgColor)
          scene.fog = new THREE.Fog(SCENE.bgColor, 40, 120)
        }}
        style={{ width: '100%', height: '100%' }}
      >
        <ambientLight intensity={0.2} />
        <pointLight position={[30, 30, 30]} intensity={0.6} />
        <pointLight position={[-20, -10, -20]} intensity={0.3} color="#06b6d4" />

        <Suspense fallback={null}>
          <HeroContent />
        </Suspense>

        <OrbitControls
          enableDamping
          enableZoom={false}
          enablePan={false}
          autoRotate
          autoRotateSpeed={0.4}
        />

        <EffectComposer>
          <Bloom
            intensity={0.8}
            luminanceThreshold={0.3}
            luminanceSmoothing={0.9}
            mipmapBlur
          />
        </EffectComposer>

        <AdaptiveDpr pixelated />
      </Canvas>
    </div>
  )
}
