'use client'

import { useEffect, useRef } from 'react'
import * as d3 from 'd3'

// Force to group nodes by cluster
function forceCluster() {
  let nodes: any[] = []
  let clusters: Map<string | number, { x: number; y: number }> = new Map()

  function force(alpha: number) {
    // Calculate cluster centers
    clusters.clear()
    for (const node of nodes) {
      const clusterId = node.clusterId
      if (!clusters.has(clusterId)) {
        clusters.set(clusterId, { x: 0, y: 0, count: 0 })
      }
      const center = clusters.get(clusterId)!
      center.x += node.x
      center.y += node.y
      center.count = (center.count || 0) + 1
    }

    // Average positions
    for (const [clusterId, center] of clusters.entries()) {
      center.x /= center.count || 1
      center.y /= center.count || 1
    }

    // Move nodes toward their cluster center
    for (const node of nodes) {
      const clusterCenter = clusters.get(node.clusterId)
      if (clusterCenter && clusterCenter.count > 1) {
        const targetX = clusterCenter.x
        const targetY = clusterCenter.y
        node.vx += (targetX - node.x) * alpha * 0.3
        node.vy += (targetY - node.y) * alpha * 0.3
      }
    }
  }

  force.initialize = function(newNodes: any[]) {
    nodes = newNodes
    return force
  }

  return force
}

interface Note {
  id: string
  title: string | null
  clusterId?: string | number
}

interface NoteCluster {
  id: string | number
  name: string
  noteIds: string[]
  color: string
}

interface BridgeNote {
  noteId: string
  bridgeScore: number
  clustersConnected?: (string | number)[]
  connectedClusterIds?: (string | number)[]
}

interface NetworkGraphProps {
  notes: Note[]
  clusters: NoteCluster[]
  bridgeNotes: BridgeNote[]
  onNoteSelect: (id: string) => void
}

export function NetworkGraph({
  notes,
  clusters,
  bridgeNotes,
  onNoteSelect
}: NetworkGraphProps) {
  const svgRef = useRef<SVGSVGElement>(null)
  const containerRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    if (!svgRef.current || !containerRef.current) return

    const width = containerRef.current.clientWidth
    const height = containerRef.current.clientHeight

    const svg = d3.select(svgRef.current)
    svg.selectAll('*').remove()

    const g = svg.append('g')

    const zoom = d3.zoom<SVGSVGElement, unknown>()
      .scaleExtent([0.1, 4])
      .on('zoom', (event) => {
        g.attr('transform', event.transform)
      })

    svg.call(zoom as any)

    // Filter notes with cluster assignments (properly check for undefined/null)
    const visibleNotes = notes.filter(n => n.clusterId !== undefined && n.clusterId !== null)

    interface D3Node extends d3.SimulationNodeDatum {
      id: string
      title: string | null
      clusterId: string | number
      color: string
      isBridge: boolean
      radius: number
    }

    interface D3Link extends d3.SimulationLinkDatum<D3Node> {
      source: string
      target: string
      strength: number
    }

    const bridgeSet = new Set(bridgeNotes.map(b => b.noteId))

    const nodes: D3Node[] = visibleNotes.map(n => {
      const cluster = clusters.find(c => c.id === String(n.clusterId))
      const isBridge = bridgeSet.has(n.id)
      return {
        id: n.id,
        title: n.title,
        clusterId: n.clusterId!,
        color: cluster?.color || '#cbd5e1',
        isBridge,
        radius: isBridge ? 12 : 8
      }
    })

    const links: D3Link[] = []
    // Connect notes within the same cluster
    for (let i = 0; i < visibleNotes.length; i++) {
      for (let j = i + 1; j < visibleNotes.length; j++) {
        const ni = visibleNotes[i]
        const nj = visibleNotes[j]

        if (ni.clusterId === nj.clusterId) {
          links.push({ source: ni.id, target: nj.id, strength: 0.5 })
        }
      }
    }

    const simulation = d3.forceSimulation<D3Node>(nodes)
      .force('link', d3.forceLink<D3Node, D3Link>(links).id(d => d.id).distance(50))
      .force('charge', d3.forceManyBody().strength(-300))
      .force('center', d3.forceCenter(width / 2, height / 2))
      .force('collision', d3.forceCollide<D3Node>().radius(d => d.radius + 15))
      .force('cluster', forceCluster())

    // Links
    const link = g.append('g')
      .selectAll('line')
      .data(links)
      .enter()
      .append('line')
      .attr('stroke', '#e2e8f0')
      .attr('stroke-opacity', 0.6)
      .attr('stroke-width', 1)

    // Nodes
    const node = g.append('g')
      .selectAll('.node')
      .data(nodes)
      .enter()
      .append('g')
      .attr('class', 'node cursor-pointer')
      .on('click', (event, d) => onNoteSelect(d.id))
      .call(d3.drag<SVGGElement, D3Node>()
        .on('start', dragstarted)
        .on('drag', dragged)
        .on('end', dragended) as any)

    node.append('circle')
      .attr('r', d => d.radius)
      .attr('fill', d => d.color)
      .attr('stroke', d => d.isBridge ? '#D4AF37' : '#fff')
      .attr('stroke-width', d => d.isBridge ? 3 : 2)
      .style('filter', d => d.isBridge ? 'drop-shadow(0 0 4px rgba(212, 175, 55, 0.4))' : 'none')

    node.append('text')
      .attr('dy', d => d.radius + 14)
      .attr('text-anchor', 'middle')
      .attr('class', 'text-[10px] fill-concrete dark:fill-concrete/60 font-medium pointer-events-none')
      .text(d => {
        const title = d.title || 'Untitled'
        return title.length > 20 ? title.substring(0, 20) + '...' : title
      })

    simulation.on('tick', () => {
      link
        .attr('x1', d => (d.source as any).x)
        .attr('y1', d => (d.source as any).y)
        .attr('x2', d => (d.target as any).x)
        .attr('y2', d => (d.target as any).y)

      node
        .attr('transform', d => `translate(${d.x},${d.y})`)
    })

    function dragstarted(event: any, d: D3Node) {
      if (!event.active) simulation.alphaTarget(0.3).restart()
      d.fx = d.x
      d.fy = d.y
    }

    function dragged(event: any, d: D3Node) {
      d.fx = event.x
      d.fy = event.y
    }

    function dragended(event: any, d: D3Node) {
      if (!event.active) simulation.alphaTarget(0)
      d.fx = null
      d.fy = null
    }

    return () => {
      simulation.stop()
    }
  }, [notes, clusters, bridgeNotes, onNoteSelect])

  return (
    <div ref={containerRef} className="w-full h-full bg-paper dark:bg-[#121212] rounded-3xl overflow-hidden border border-border/40 relative">
      <div className="absolute top-6 left-6 z-10 flex flex-wrap gap-3 max-w-[300px]">
        {clusters.map(c => (
          <div key={c.id} className="flex items-center gap-1.5 px-2 py-1 bg-white/80 dark:bg-white/5 backdrop-blur-sm border border-border rounded-full shadow-sm">
            <div className="w-2 h-2 rounded-full" style={{ backgroundColor: c.color }} />
            <span className="text-[9px] font-bold uppercase tracking-widest text-concrete whitespace-nowrap">{c.name}</span>
          </div>
        ))}
      </div>
      <svg ref={svgRef} className="w-full h-full" />
    </div>
  )
}
