import { useRef, useMemo, useEffect } from 'react'
import { useFrame } from '@react-three/fiber'
import * as THREE from 'three'
import type { TransformedGraph } from './types'

interface EdgeLinesProps {
  graph: TransformedGraph
  positions: Float32Array
  highlightSet: Set<number> | null
}

export default function EdgeLines({ graph, positions, highlightSet }: EdgeLinesProps) {
  const lineRef = useRef<THREE.LineSegments>(null!)
  const vertexCount = graph.edges.length * 2
  const maxDegree = useMemo(() => Math.max(1, ...graph.nodes.map(n => n.degree)), [graph])

  const posArray = useMemo(() => new Float32Array(vertexCount * 3), [vertexCount])
  const colArray = useMemo(() => new Float32Array(vertexCount * 3), [vertexCount])

  // Set up geometry imperatively
  useEffect(() => {
    const line = lineRef.current
    if (!line) return
    const geo = new THREE.BufferGeometry()
    geo.setAttribute('position', new THREE.BufferAttribute(posArray, 3))
    geo.setAttribute('color', new THREE.BufferAttribute(colArray, 3))
    line.geometry = geo
  }, [posArray, colArray])

  useFrame(() => {
    if (!positions || !lineRef.current?.geometry) return

    for (let i = 0; i < graph.edges.length; i++) {
      const e = graph.edges[i]
      const base = i * 6

      posArray[base]     = positions[e.sourceIndex * 3]
      posArray[base + 1] = positions[e.sourceIndex * 3 + 1]
      posArray[base + 2] = positions[e.sourceIndex * 3 + 2]
      posArray[base + 3] = positions[e.targetIndex * 3]
      posArray[base + 4] = positions[e.targetIndex * 3 + 1]
      posArray[base + 5] = positions[e.targetIndex * 3 + 2]

      const active = !highlightSet || (highlightSet.has(e.sourceIndex) && highlightSet.has(e.targetIndex))
      // Degree-based glow: edges between highly-connected nodes shine brighter
      const srcDeg = graph.nodes[e.sourceIndex]?.degree || 0
      const tgtDeg = graph.nodes[e.targetIndex]?.degree || 0
      const avgDeg = (srcDeg + tgtDeg) / 2
      const degreeGlow = 0.3 + 0.7 * Math.pow(avgDeg / maxDegree, 0.5)
      const brightness = highlightSet ? (active ? 1.2 : 0.06) : 0.5 * degreeGlow

      // Cyan-tinted edges
      colArray[base]     = 0.1 * brightness
      colArray[base + 1] = 0.7 * brightness
      colArray[base + 2] = 0.85 * brightness
      colArray[base + 3] = colArray[base]
      colArray[base + 4] = colArray[base + 1]
      colArray[base + 5] = colArray[base + 2]
    }

    const geo = lineRef.current.geometry
    if (geo.attributes.position) geo.attributes.position.needsUpdate = true
    if (geo.attributes.color) geo.attributes.color.needsUpdate = true
  })

  return (
    <lineSegments ref={lineRef} frustumCulled={false}>
      <lineBasicMaterial vertexColors transparent opacity={0.6} depthWrite={false} />
    </lineSegments>
  )
}
