'use client'

import { useCallback, useMemo, useEffect } from 'react'
import ReactFlow, {
  Background,
  Controls,
  MiniMap,
  Node,
  Edge,
  Connection,
  useNodesState,
  useEdgesState,
  addEdge,
  NodeTypes,
  EdgeTypes,
  ReactFlowProvider,
} from 'reactflow'
import 'reactflow/dist/style.css'
import type { NetworkTopology } from '@/lib/types/infrastructure'
import { RegionNode } from './nodes/RegionNode'
import { DatacenterNode } from './nodes/DatacenterNode'
import { TunnelNode } from './nodes/TunnelNode'
import { VMNode } from './nodes/VMNode'
import { ServiceNode } from './nodes/ServiceNode'
import { CustomEdge } from './edges/CustomEdge'

interface ReactFlowTopologyProps {
  topology: NetworkTopology
  editMode: boolean
  onNodesChange?: (nodes: Node[]) => void
  onEdgesChange?: (edges: Edge[]) => void
  onConnect?: (connection: Connection) => void
  onNodeClick?: (node: Node) => void
  onEdgeClick?: (edge: Edge) => void
}

const nodeTypes: NodeTypes = {
  region: RegionNode,
  datacenter: DatacenterNode,
  tunnel: TunnelNode,
  vm: VMNode,
  service: ServiceNode,
}

const edgeTypes: EdgeTypes = {
  default: CustomEdge,
  tunnel: CustomEdge,
  peering: CustomEdge,
  'network-route': CustomEdge,
}

export function ReactFlowTopology({
  topology,
  editMode,
  onNodesChange: externalOnNodesChange,
  onEdgesChange: externalOnEdgesChange,
  onConnect: externalOnConnect,
  onNodeClick,
  onEdgeClick,
}: ReactFlowTopologyProps) {
  // Convert topology data to React Flow format
  const initialNodes: Node[] = useMemo(
    () =>
      topology.nodes.map((node) => ({
        id: node.id,
        type: node.type,
        position: node.position,
        data: {
          label: node.label,
          region: node.region,
          entity: node.entity,
          metadata: node.metadata,
        },
      })),
    [topology.nodes]
  )

  const initialEdges: Edge[] = useMemo(
    () =>
      topology.edges.map((edge) => ({
        id: edge.id,
        source: edge.source,
        target: edge.target,
        type: edge.type || 'default',
        data: {
          metadata: edge.metadata,
        },
      })),
    [topology.edges]
  )

  const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes)
  const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges)

  // Sync with external changes
  useEffect(() => {
    setNodes(initialNodes)
  }, [initialNodes, setNodes])

  useEffect(() => {
    setEdges(initialEdges)
  }, [initialEdges, setEdges])

  const handleNodesChange = useCallback(
    (changes: any) => {
      onNodesChange(changes)
      const updatedNodes = nodes.map((node) => {
        const change = changes.find((c: any) => c.id === node.id)
        if (change && change.type === 'position' && change.position) {
          return { ...node, position: change.position }
        }
        return node
      })
      externalOnNodesChange?.(updatedNodes)
    },
    [nodes, onNodesChange, externalOnNodesChange]
  )

  const handleEdgesChange = useCallback(
    (changes: any) => {
      onEdgesChange(changes)
      externalOnEdgesChange?.(edges)
    },
    [edges, onEdgesChange, externalOnEdgesChange]
  )

  const handleConnect = useCallback(
    (connection: Connection) => {
      const newEdge = addEdge(connection, edges)
      setEdges(newEdge)
      externalOnConnect?.(connection)
    },
    [edges, setEdges, externalOnConnect]
  )

  return (
    <ReactFlowProvider>
      <div className="w-full h-[600px] border border-studio-medium rounded-lg bg-studio-black">
        <ReactFlow
          nodes={nodes}
          edges={edges}
          onNodesChange={handleNodesChange}
          onEdgesChange={handleEdgesChange}
          onConnect={editMode ? handleConnect : undefined}
          onNodeClick={onNodeClick}
          onEdgeClick={onEdgeClick}
          nodeTypes={nodeTypes}
          edgeTypes={edgeTypes}
          fitView
          minZoom={0.1}
          maxZoom={2}
          defaultViewport={{ x: 0, y: 0, zoom: 1 }}
        >
          <Background color="#374151" gap={16} />
          <Controls />
          <MiniMap
            nodeColor={(node) => {
              const colors: Record<string, string> = {
                region: '#3b82f6',
                datacenter: '#10b981',
                tunnel: '#8b5cf6',
                vm: '#f59e0b',
                service: '#ef4444',
              }
              return colors[node.type || 'service'] || '#6b7280'
            }}
            maskColor="rgba(0, 0, 0, 0.8)"
          />
        </ReactFlow>
      </div>
    </ReactFlowProvider>
  )
}

