'use client'

import { useState, useRef, useCallback, useEffect, useMemo, memo } from 'react'
import { useNetworkTopologies } from '@/lib/hooks/useInfrastructureData'
import { useMutation } from '@apollo/client'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Button } from '@/components/ui/button'
import { RegionSelector } from './RegionSelector'
import { EntitySelector } from './EntitySelector'
import { EditModeToggle } from './EditModeToggle'
import { EditTopologyNodeForm } from './forms/EditTopologyNodeForm'
import { Download, Plus, Trash2, Undo, Redo, HelpCircle } from 'lucide-react'
import { ReactFlowTopology } from './lazy'
import { EmptyState } from './EmptyState'
import { KeyboardShortcuts, useKeyboardShortcuts } from './KeyboardShortcuts'
import { ConfirmDialog } from './ConfirmDialog'
import { NodeDetailsPanel } from './NodeDetailsPanel'
import { useToast } from '@/components/ui/use-toast'
import html2canvas from 'html2canvas'
import { UPDATE_NETWORK_TOPOLOGY } from '@/lib/graphql/queries/infrastructure'
import type { NetworkTopology, TopologyNode, TopologyEdge } from '@/lib/types/infrastructure'

// Use React Flow for topology visualization (fallback to SVG if React Flow fails)
function TopologyVisualizationWrapper({
  topology,
  editMode,
  containerRef,
  onNodeDrag,
  onNodeClick,
  onNodeDelete,
  onEdgeDelete,
  selectedNodeId,
  connectingFrom,
  useReactFlow = true,
}: {
  topology: NetworkTopology
  editMode: boolean
  containerRef: React.RefObject<HTMLDivElement>
  onNodeDrag?: (nodeId: string, x: number, y: number) => void
  onNodeClick?: (nodeId: string) => void
  onNodeDelete?: (nodeId: string) => void
  onEdgeDelete?: (edgeId: string) => void
  selectedNodeId?: string | null
  connectingFrom?: string | null
  useReactFlow?: boolean
}) {
  if (useReactFlow) {
    return (
      <div ref={containerRef} id="topology-container">
        <ReactFlowTopology
          topology={topology}
          editMode={editMode}
          onNodesChange={(nodes) => {
            // Update local topology when nodes change
            const updatedNodes = nodes.map((node) => ({
              id: node.id,
              type: node.type as any,
              label: node.data.label,
              region: node.data.region,
              entity: node.data.entity,
              position: node.position,
              metadata: node.data.metadata || {},
            }))
            // This will be handled by parent component
          }}
          onNodeClick={(node) => onNodeClick?.(node.id)}
        />
      </div>
    )
  }

  // Fallback to simple SVG visualization
  return (
    <div
      ref={containerRef}
      id="topology-container"
      className="relative w-full h-[600px] border border-studio-medium rounded-lg bg-studio-black overflow-hidden"
    >
      <svg
        id="topology-svg"
        width="100%"
        height="100%"
        viewBox="0 0 800 600"
        className="absolute inset-0"
      >
        {/* Simple SVG fallback */}
        {topology.edges.map((edge) => {
          const sourceNode = topology.nodes.find((n) => n.id === edge.source)
          const targetNode = topology.nodes.find((n) => n.id === edge.target)
          if (!sourceNode || !targetNode) return null
          return (
            <line
              key={edge.id}
              x1={sourceNode.position.x}
              y1={sourceNode.position.y}
              x2={targetNode.position.x}
              y2={targetNode.position.y}
              stroke="#3b82f6"
              strokeWidth="2"
            />
          )
        })}
        {topology.nodes.map((node) => (
          <circle
            key={node.id}
            cx={node.position.x}
            cy={node.position.y}
            r={20}
            fill="#3b82f6"
            onClick={() => onNodeClick?.(node.id)}
            className="cursor-pointer"
          />
        ))}
      </svg>
    </div>
  )
}

export function NetworkTopologyDocs() {
  const [selectedRegion, setSelectedRegion] = useState<string>('All')
  const [selectedEntity, setSelectedEntity] = useState<string>('All')
  const [editMode, setEditMode] = useState(false)
  const [exporting, setExporting] = useState(false)
  const [localTopology, setLocalTopology] = useState<NetworkTopology | null>(null)
  const [history, setHistory] = useState<NetworkTopology[]>([])
  const [historyIndex, setHistoryIndex] = useState(-1)
  const [selectedNodeId, setSelectedNodeId] = useState<string | null>(null)
  const [connectingFrom, setConnectingFrom] = useState<string | null>(null)
  const [editingNode, setEditingNode] = useState<TopologyNode | null>(null)
  const [dialogOpen, setDialogOpen] = useState(false)
  const [shortcutsOpen, setShortcutsOpen] = useState(false)
  const [confirmDelete, setConfirmDelete] = useState<{ type: 'node' | 'edge'; id: string } | null>(null)
  const topologyRef = useRef<HTMLDivElement>(null)
  const { toast } = useToast()

  // Keyboard shortcuts
  useKeyboardShortcuts([
    {
      keys: ['Ctrl', 'e'],
      handler: () => setEditMode(!editMode),
      description: 'Toggle edit mode',
    },
    {
      keys: ['Ctrl', 's'],
      handler: () => {
        if (editMode && localTopology) {
          handleSave()
        }
      },
      description: 'Save changes',
    },
    {
      keys: ['Escape'],
      handler: () => {
        setEditMode(false)
        setSelectedNodeId(null)
        setConnectingFrom(null)
      },
      description: 'Cancel/Exit',
    },
    {
      keys: ['Ctrl', '/'],
      handler: () => setShortcutsOpen(true),
      description: 'Show shortcuts',
    },
  ])

  const [updateTopology, { loading: saving }] = useMutation(UPDATE_NETWORK_TOPOLOGY, {
    refetchQueries: ['GetNetworkTopologies'],
  })

  const filter = {
    region: selectedRegion === 'All' ? undefined : selectedRegion,
    entity: selectedEntity === 'All' ? undefined : selectedEntity,
  }

  const { topologies, loading, error } = useNetworkTopologies(filter)

  // Initialize local topology when data loads
  useEffect(() => {
    if (topologies.length > 0 && !localTopology) {
      const topology = topologies[0]
      setLocalTopology(topology)
      setHistory([topology])
      setHistoryIndex(0)
    }
  }, [topologies, localTopology])

  // Save state to history for undo/redo
  const saveToHistory = useCallback((topology: NetworkTopology) => {
    setHistory((prev) => {
      const newHistory = prev.slice(0, historyIndex + 1)
      newHistory.push(topology)
      return newHistory.slice(-50) // Keep last 50 states
    })
    setHistoryIndex((prev) => Math.min(prev + 1, 49))
  }, [historyIndex])

  const handleNodeDrag = useCallback((nodeId: string, x: number, y: number) => {
    if (!localTopology) return

    const updatedNodes = localTopology.nodes.map((node) =>
      node.id === nodeId ? { ...node, position: { x, y } } : node
    )

    const updated = { ...localTopology, nodes: updatedNodes }
    setLocalTopology(updated)
  }, [localTopology])

  const handleNodeClick = useCallback((nodeId: string) => {
    if (connectingFrom) {
      // Create edge
      if (connectingFrom !== nodeId && localTopology) {
        const newEdge: TopologyEdge = {
          id: `edge-${Date.now()}`,
          source: connectingFrom,
          target: nodeId,
          type: 'network-route',
          metadata: {},
        }

        const updated = {
          ...localTopology,
          edges: [...localTopology.edges, newEdge],
        }
        setLocalTopology(updated)
        saveToHistory(updated)
        setConnectingFrom(null)
        toast({
          title: 'Edge created',
          description: 'Connection added successfully',
        })
      } else {
        setConnectingFrom(null)
      }
    } else {
      setSelectedNodeId(nodeId)
    }
  }, [connectingFrom, localTopology, saveToHistory, toast])

  const selectedNode = displayTopology?.nodes.find((n) => n.id === selectedNodeId) || null

  const handleNodeDelete = useCallback((nodeId: string) => {
    if (!localTopology) return

    const updated = {
      ...localTopology,
      nodes: localTopology.nodes.filter((n) => n.id !== nodeId),
      edges: localTopology.edges.filter((e) => e.source !== nodeId && e.target !== nodeId),
    }
    setLocalTopology(updated)
    saveToHistory(updated)
    setSelectedNodeId(null)
    toast({
      title: 'Node deleted',
      description: 'Node and its connections removed',
    })
  }, [localTopology, saveToHistory, toast])

  const handleEdgeDelete = useCallback((edgeId: string) => {
    if (!localTopology) return

    const updated = {
      ...localTopology,
      edges: localTopology.edges.filter((e) => e.id !== edgeId),
    }
    setLocalTopology(updated)
    saveToHistory(updated)
    toast({
      title: 'Edge deleted',
      description: 'Connection removed',
    })
  }, [localTopology, saveToHistory, toast])

  const handleAddNode = useCallback(() => {
    if (!localTopology) return

    const newNode: TopologyNode = {
      id: `node-${Date.now()}`,
      type: 'service',
      label: 'New Node',
      region: localTopology.region,
      entity: localTopology.entity,
      position: { x: 400, y: 300 },
      metadata: {},
    }

    const updated = {
      ...localTopology,
      nodes: [...localTopology.nodes, newNode],
    }
    setLocalTopology(updated)
    saveToHistory(updated)
    setSelectedNodeId(newNode.id)
    toast({
      title: 'Node added',
      description: 'New node created',
    })
  }, [localTopology, saveToHistory, toast])

  const handleUndo = useCallback(() => {
    if (historyIndex > 0) {
      const newIndex = historyIndex - 1
      setHistoryIndex(newIndex)
      setLocalTopology(history[newIndex])
    }
  }, [history, historyIndex])

  const handleRedo = useCallback(() => {
    if (historyIndex < history.length - 1) {
      const newIndex = historyIndex + 1
      setHistoryIndex(newIndex)
      setLocalTopology(history[newIndex])
    }
  }, [history, historyIndex])

  const handleSave = useCallback(async () => {
    if (!localTopology) return

    try {
      await updateTopology({
        variables: {
          id: localTopology.id || 'default',
          input: {
            nodes: localTopology.nodes,
            edges: localTopology.edges,
            lastUpdated: new Date().toISOString(),
          },
        },
      })

      toast({
        title: 'Saved',
        description: 'Topology changes saved successfully',
        variant: 'success',
      })
    } catch (error) {
      toast({
        title: 'Save failed',
        description: error instanceof Error ? error.message : 'Failed to save topology',
        variant: 'error',
      })
    }
  }, [localTopology, updateTopology, toast])

  const handleExportPNG = async () => {
    if (!topologyRef.current) {
      toast({
        title: 'Export failed',
        description: 'Topology container not found',
        variant: 'error',
      })
      return
    }

    setExporting(true)
    try {
      const canvas = await html2canvas(topologyRef.current, {
        backgroundColor: '#000000',
        scale: 2, // High resolution
        logging: false,
        useCORS: true,
      })

      canvas.toBlob(
        (blob) => {
          if (!blob) {
            toast({
              title: 'Export failed',
              description: 'Failed to create image blob',
              variant: 'error',
            })
            return
          }

          const url = URL.createObjectURL(blob)
          const a = document.createElement('a')
          a.href = url
          a.download = `topology-${selectedRegion}-${selectedEntity}-${Date.now()}.png`
          document.body.appendChild(a)
          a.click()
          document.body.removeChild(a)
          URL.revokeObjectURL(url)

          toast({
            title: 'Export successful',
            description: 'Topology exported as PNG',
          })
        },
        'image/png',
        1.0
      )
    } catch (error) {
      toast({
        title: 'Export failed',
        description: error instanceof Error ? error.message : 'Unknown error occurred',
        variant: 'error',
      })
    } finally {
      setExporting(false)
    }
  }

  const handleExportSVG = () => {
    const svgElement = topologyRef.current?.querySelector('#topology-svg') as SVGElement
    if (!svgElement) {
      toast({
        title: 'Export failed',
        description: 'SVG element not found',
        variant: 'error',
      })
      return
    }

    try {
      // Clone the SVG to avoid modifying the original
      const svgClone = svgElement.cloneNode(true) as SVGElement
      
      // Set explicit dimensions
      const bbox = svgElement.getBBox()
      svgClone.setAttribute('width', bbox.width.toString())
      svgClone.setAttribute('height', bbox.height.toString())
      svgClone.setAttribute('viewBox', `${bbox.x} ${bbox.y} ${bbox.width} ${bbox.height}`)

      // Serialize to string
      const svgData = new XMLSerializer().serializeToString(svgClone)
      const svgBlob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' })
      const url = URL.createObjectURL(svgBlob)
      const a = document.createElement('a')
      a.href = url
      a.download = `topology-${selectedRegion}-${selectedEntity}-${Date.now()}.svg`
      document.body.appendChild(a)
      a.click()
      document.body.removeChild(a)
      URL.revokeObjectURL(url)

      toast({
        title: 'Export successful',
        description: 'Topology exported as SVG',
      })
    } catch (error) {
      toast({
        title: 'Export failed',
        description: error instanceof Error ? error.message : 'Unknown error occurred',
        variant: 'error',
      })
    }
  }

  if (loading) {
    return (
      <div className="space-y-6">
        <div>
          <h1 className="text-3xl font-bold text-studio-light">Network Topology</h1>
          <p className="text-studio-medium mt-2">
            Visualize and manage network topology by region and entity
          </p>
        </div>
        <Card>
          <CardContent>
            <div className="h-[600px] flex items-center justify-center">
              <div className="text-studio-medium">Loading topology...</div>
            </div>
          </CardContent>
        </Card>
      </div>
    )
  }

  if (error) {
    return (
      <Card>
        <CardHeader>
          <CardTitle>Error Loading Topology</CardTitle>
          <CardDescription>{error.message}</CardDescription>
        </CardHeader>
      </Card>
    )
  }

  const displayTopology = useMemo(() => localTopology || topologies[0], [localTopology, topologies])

  return (
    <div className="space-y-6">
      <div className="flex items-center justify-between">
        <div>
          <h1 className="text-3xl font-bold text-studio-light">Network Topology</h1>
          <p className="text-studio-medium mt-2">
            Visualize and manage network topology by region and entity
          </p>
        </div>
        <div className="flex gap-2">
          {editMode && (
            <>
              <Button variant="outline" onClick={handleUndo} disabled={historyIndex <= 0}>
                <Undo className="h-4 w-4 mr-2" />
                Undo
              </Button>
              <Button variant="outline" onClick={handleRedo} disabled={historyIndex >= history.length - 1}>
                <Redo className="h-4 w-4 mr-2" />
                Redo
              </Button>
              <Button onClick={handleSave} disabled={saving || !localTopology}>
                {saving ? 'Saving...' : 'Save Changes'}
              </Button>
            </>
          )}
          <Button variant="outline" onClick={handleExportPNG} disabled={exporting || !topologies.length}>
            <Download className="h-4 w-4 mr-2" />
            {exporting ? 'Exporting...' : 'Export PNG'}
          </Button>
          <Button variant="outline" onClick={handleExportSVG} disabled={!topologies.length}>
            <Download className="h-4 w-4 mr-2" />
            Export SVG
          </Button>
          <Button variant="outline" onClick={() => setShortcutsOpen(true)}>
            <HelpCircle className="h-4 w-4 mr-2" />
            Shortcuts
          </Button>
        </div>
      </div>

      <Card>
        <CardHeader>
          <div className="flex items-center justify-between">
            <div>
              <CardTitle>Topology Diagram</CardTitle>
              <CardDescription>
                {topologies.length} topology{topologies.length !== 1 ? 'ies' : ''} found
              </CardDescription>
            </div>
            <div className="flex items-center gap-4">
              <RegionSelector
                value={selectedRegion}
                onChange={setSelectedRegion}
                className="w-48"
              />
              <EntitySelector
                value={selectedEntity}
                onChange={setSelectedEntity}
                className="w-64"
              />
              <EditModeToggle enabled={editMode} onToggle={setEditMode} />
            </div>
          </div>
        </CardHeader>
        <CardContent>
          {displayTopology ? (
            <>
              {editMode && (
                <div className="mb-4 flex gap-2 p-4 bg-studio-medium/20 rounded-lg">
                  <Button size="sm" onClick={handleAddNode}>
                    <Plus className="h-4 w-4 mr-2" />
                    Add Node
                  </Button>
                  <Button
                    size="sm"
                    variant={connectingFrom ? 'default' : 'outline'}
                    onClick={() => {
                      if (connectingFrom) {
                        setConnectingFrom(null)
                      } else if (selectedNodeId) {
                        setConnectingFrom(selectedNodeId)
                      } else {
                        toast({
                          title: 'Select a node',
                          description: 'Please select a node to start connecting',
                          variant: 'error',
                        })
                      }
                    }}
                  >
                    {connectingFrom ? 'Cancel Connection' : 'Connect Nodes'}
                  </Button>
                  {selectedNodeId && (
                    <>
                      <Button
                        size="sm"
                        variant="outline"
                        onClick={() => {
                          const node = displayTopology.nodes.find((n) => n.id === selectedNodeId)
                          if (node) {
                            setEditingNode(node)
                            setDialogOpen(true)
                          }
                        }}
                      >
                        Edit Node
                      </Button>
                      <Button
                        size="sm"
                        variant="outline"
                        onClick={() => {
                          setConfirmDelete({ type: 'node', id: selectedNodeId })
                        }}
                      >
                        <Trash2 className="h-4 w-4 mr-2" />
                        Delete Node
                      </Button>
                    </>
                  )}
                </div>
              )}
              <TopologyVisualizationWrapper
                topology={displayTopology}
                editMode={editMode}
                containerRef={topologyRef}
                onNodeDrag={handleNodeDrag}
                onNodeClick={handleNodeClick}
                onNodeDelete={handleNodeDelete}
                onEdgeDelete={handleEdgeDelete}
                selectedNodeId={selectedNodeId}
                connectingFrom={connectingFrom}
                useReactFlow={true}
              />
            </>
          ) : (
            <EmptyState
              title="No topology data"
              description="No topology data available for the selected filters."
              action={{
                label: 'Clear Filters',
                onClick: () => {
                  setSelectedRegion('All')
                  setSelectedEntity('All')
                },
              }}
            />
          )}
        </CardContent>
      </Card>

      {editingNode && displayTopology && (
        <EditTopologyNodeForm
          open={dialogOpen}
          onOpenChange={(open) => {
            setDialogOpen(open)
            if (!open) {
              setEditingNode(null)
              setSelectedNodeId(null)
            }
          }}
          node={editingNode}
          topologyId={displayTopology.id || 'default'}
          onSuccess={() => {
            // Refresh topology after edit
            if (topologies.length > 0) {
              setLocalTopology(topologies[0])
            }
            setEditingNode(null)
            setSelectedNodeId(null)
          }}
        />
      )}

      <KeyboardShortcuts
        open={shortcutsOpen}
        onOpenChange={setShortcutsOpen}
        shortcuts={[
          { keys: ['Ctrl', 'E'], description: 'Toggle edit mode', category: 'General' },
          { keys: ['Ctrl', 'S'], description: 'Save changes', category: 'General' },
          { keys: ['Escape'], description: 'Cancel/Exit', category: 'General' },
          { keys: ['Ctrl', '/'], description: 'Show shortcuts', category: 'General' },
          ]}
        />

        {selectedNode && displayTopology && (
          <NodeDetailsPanel
            node={selectedNode}
            topology={displayTopology}
            onClose={() => setSelectedNodeId(null)}
            onEdit={() => {
              setEditingNode(selectedNode)
              setDialogOpen(true)
            }}
            onDelete={() => {
              setConfirmDelete({ type: 'node', id: selectedNode.id })
            }}
          />
        )}

        {confirmDelete && (
          <ConfirmDialog
            open={!!confirmDelete}
            onOpenChange={(open) => {
              if (!open) setConfirmDelete(null)
            }}
            title={confirmDelete.type === 'node' ? 'Delete Node' : 'Delete Edge'}
            description={
              confirmDelete.type === 'node'
                ? 'Are you sure you want to delete this node and all its connections? This action cannot be undone.'
                : 'Are you sure you want to delete this connection? This action cannot be undone.'
            }
            confirmLabel="Delete"
            variant="destructive"
            onConfirm={() => {
              if (confirmDelete.type === 'node') {
                handleNodeDelete(confirmDelete.id)
              } else {
                handleEdgeDelete(confirmDelete.id)
              }
              setConfirmDelete(null)
            }}
          />
        )}
      </div>
    )
  }

