import React, {
  useRef,
  useEffect,
  useState,
  useCallback,
  useMemo,
} from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Separator } from "@/components/ui/separator";
import {
  ArrowLeft,
  Search,
  ZoomIn,
  ZoomOut,
  RotateCcw,
  Download,
} from "lucide-react";
import {
  UniversalGraphData,
  UniversalNode,
  UniversalLink,
  GraphVisualizationConfig,
  GraphSelectionCallbacks,
  GraphInteractionState,
  GraphStats,
} from "@/types/graph-visualization";
import { CytoscapeGraphCore } from "@/lib/cytoscape-graph-core";

interface BaseGraphVisualizerProps {
  data: UniversalGraphData;
  config: GraphVisualizationConfig;
  onBack?: () => void;
  title?: string;
  subtitle?: string;
  className?: string;
  children?: React.ReactNode;
}

export const BaseGraphVisualizer: React.FC<BaseGraphVisualizerProps> = ({
  data,
  config,
  onBack,
  title = "Graph Visualization",
  subtitle,
  className = "",
  children,
}) => {
  const containerRef = useRef<HTMLDivElement>(null);
  const cytoscapeRef = useRef<CytoscapeGraphCore | null>(null);

  // State management
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [interactionState, setInteractionState] =
    useState<GraphInteractionState>({
      selectedElement: null,
      selectedElementType: null,
      hoveredElement: null,
      searchTerm: "",
      highlightedElements: new Set(),
    });

  // Graph statistics
  const [stats, setStats] = useState<GraphStats>({
    nodeCount: 0,
    linkCount: 0,
    nodeTypes: {},
    linkTypes: {},
    averageDegree: 0,
    maxDegree: 0,
    connectedComponents: 1,
  });

  // Calculate graph statistics
  const calculateStats = useCallback(
    (graphData: UniversalGraphData): GraphStats => {
      const nodeTypes: Record<string, number> = {};
      const linkTypes: Record<string, number> = {};
      const nodeDegrees: Record<string, number> = {};

      // Count node types
      graphData.nodes.forEach((node) => {
        const type = node.type || "Unknown";
        nodeTypes[type] = (nodeTypes[type] || 0) + 1;
        nodeDegrees[node.id] = 0;
      });

      // Count link types and node degrees
      graphData.links.forEach((link) => {
        const type = link.type || "Unknown";
        linkTypes[type] = (linkTypes[type] || 0) + 1;

        const sourceId =
          typeof link.source === "string" ? link.source : link.source.id;
        const targetId =
          typeof link.target === "string" ? link.target : link.target.id;

        nodeDegrees[sourceId] = (nodeDegrees[sourceId] || 0) + 1;
        nodeDegrees[targetId] = (nodeDegrees[targetId] || 0) + 1;
      });

      const degrees = Object.values(nodeDegrees);
      const averageDegree =
        degrees.length > 0
          ? degrees.reduce((a, b) => a + b, 0) / degrees.length
          : 0;
      const maxDegree = degrees.length > 0 ? Math.max(...degrees) : 0;

      return {
        nodeCount: graphData.nodes.length,
        linkCount: graphData.links.length,
        nodeTypes,
        linkTypes,
        averageDegree: Math.round(averageDegree * 100) / 100,
        maxDegree,
        connectedComponents: 1, // Simplified for now
      };
    },
    []
  );

  // Selection callbacks - wrapped in useMemo to prevent recreation on every render
  const selectionCallbacks = useMemo(
    (): GraphSelectionCallbacks => ({
      onNodeSelect: (node: UniversalNode) => {
        setInteractionState((prev) => ({
          ...prev,
          selectedElement: node,
          selectedElementType: "node",
        }));
      },
      onLinkSelect: (link: UniversalLink) => {
        setInteractionState((prev) => ({
          ...prev,
          selectedElement: link,
          selectedElementType: "link",
        }));
      },
      onClearSelection: () => {
        setInteractionState((prev) => ({
          ...prev,
          selectedElement: null,
          selectedElementType: null,
        }));
      },
    }),
    []
  );

  // Initialize Cytoscape visualization
  useEffect(() => {
    console.log("BaseGraphVisualizer: useEffect triggered", {
      containerRef: !!containerRef.current,
      dataNodes: data.nodes.length,
      dataLinks: data.links.length,
    });

    const initializeVisualization = async () => {
      try {
        if (!containerRef.current) {
          console.log(
            "BaseGraphVisualizer: Container ref not ready during initialization"
          );
          return;
        }

        // Wait for layout to settle
        await new Promise((resolve) => setTimeout(resolve, 200));

        const container = containerRef.current;
        let width = container.clientWidth || config.width;
        let height = container.clientHeight || config.height;

        // If container has zero dimensions, try to get parent dimensions
        if (width === 0 || height === 0) {
          const parent = container.parentElement;
          if (parent) {
            width = parent.clientWidth || config.width;
            height = parent.clientHeight || config.height;
            console.log("BaseGraphVisualizer: Using parent dimensions", {
              parentWidth: width,
              parentHeight: height,
            });
          }
        }

        const finalConfig = {
          ...config,
          width: Math.max(width, 400),
          height: Math.max(height, 400),
        };

        console.log(
          "BaseGraphVisualizer: Initializing with config",
          finalConfig
        );

        cytoscapeRef.current = new CytoscapeGraphCore(
          containerRef.current,
          finalConfig,
          selectionCallbacks
        );

        // Load data
        console.log("BaseGraphVisualizer: Loading data", {
          nodes: data.nodes.length,
          links: data.links.length,
        });
        cytoscapeRef.current.updateGraph(data, true);

        // Calculate and set statistics
        setStats(calculateStats(data));
        console.log(
          "BaseGraphVisualizer: Initialization complete, setting loading to false"
        );
        setLoading(false);
      } catch (err) {
        console.error("BaseGraphVisualizer: Error initializing:", err);
        setError(
          `Failed to initialize visualization: ${
            err instanceof Error ? err.message : String(err)
          }`
        );
        setLoading(false);
      }
    };

    // Function to check if refs are ready and initialize
    const checkAndInitialize = () => {
      if (!containerRef.current) {
        console.log("BaseGraphVisualizer: Missing container ref, retrying...");
        return false;
      }
      return true;
    };

    // If refs not ready immediately, set up a retry mechanism
    if (!checkAndInitialize()) {
      let retryCount = 0;
      const maxRetries = 20;

      const retryInterval = setInterval(() => {
        retryCount++;
        console.log(
          `BaseGraphVisualizer: Retry attempt ${retryCount}/${maxRetries}`
        );

        if (checkAndInitialize()) {
          clearInterval(retryInterval);
          initializeVisualization();
        } else if (retryCount >= maxRetries) {
          clearInterval(retryInterval);
          console.error("BaseGraphVisualizer: Max retries reached, giving up");
          setError(
            "Failed to initialize visualization: DOM elements not ready"
          );
          setLoading(false);
        }
      }, 200);

      return () => {
        clearInterval(retryInterval);
        if (cytoscapeRef.current) {
          cytoscapeRef.current.destroy();
          cytoscapeRef.current = null;
        }
      };
    }

    // If refs are ready, initialize immediately
    const timeoutId = setTimeout(initializeVisualization, 100);

    // Cleanup
    return () => {
      clearTimeout(timeoutId);
      if (cytoscapeRef.current) {
        cytoscapeRef.current.destroy();
        cytoscapeRef.current = null;
      }
    };
  }, [data, config, calculateStats, selectionCallbacks]);

  // Handle search
  const handleSearch = useCallback(
    (searchTerm: string) => {
      setInteractionState((prev) => ({
        ...prev,
        searchTerm,
        highlightedElements: new Set(
          data.nodes
            .filter(
              (node) =>
                node.name?.toLowerCase().includes(searchTerm.toLowerCase()) ||
                node.label?.toLowerCase().includes(searchTerm.toLowerCase()) ||
                node.id.toLowerCase().includes(searchTerm.toLowerCase())
            )
            .map((node) => node.id)
        ),
      }));
    },
    [data.nodes]
  );

  // Control handlers
  const handleZoomIn = () => cytoscapeRef.current?.zoomIn();
  const handleZoomOut = () => cytoscapeRef.current?.zoomOut();
  const handleResetZoom = () => cytoscapeRef.current?.resetZoom();

  const handleDownload = () => {
    if (!cytoscapeRef.current) return;

    // For Cytoscape, we'll export as PNG instead of SVG
    const cy = cytoscapeRef.current.getCytoscape();
    if (!cy) return;

    const pngData = cy.png({ scale: 2, full: true });
    const downloadLink = document.createElement("a");
    downloadLink.href = pngData;
    downloadLink.download = `graph-${Date.now()}.png`;
    document.body.appendChild(downloadLink);
    downloadLink.click();
    document.body.removeChild(downloadLink);
  };

  // Handle window resize
  useEffect(() => {
    const handleResize = () => {
      if (cytoscapeRef.current && containerRef.current) {
        const container = containerRef.current;
        const width = container.clientWidth;
        const height = container.clientHeight;
        cytoscapeRef.current.resize(width, height);
      }
    };

    window.addEventListener("resize", handleResize);
    return () => window.removeEventListener("resize", handleResize);
  }, []);

  if (loading) {
    return (
      <div className="flex items-center justify-center h-96">
        <div className="text-center">
          <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto mb-4"></div>
          <p className="text-muted-foreground">Loading visualization...</p>
        </div>
      </div>
    );
  }

  if (error) {
    return (
      <div className="flex items-center justify-center h-96">
        <div className="text-center">
          <div className="text-red-500 mb-4">⚠️</div>
          <p className="text-red-600 font-medium">Visualization Error</p>
          <p className="text-muted-foreground text-sm mt-2">{error}</p>
        </div>
      </div>
    );
  }

  return (
    <div className={`flex flex-col h-full ${className}`}>
      {/* Header */}
      <div className="flex items-center justify-between p-4 border-b">
        <div className="flex items-center space-x-4">
          {onBack && (
            <Button variant="ghost" size="sm" onClick={onBack}>
              <ArrowLeft className="h-4 w-4 mr-2" />
              Back
            </Button>
          )}
          <div>
            <h1 className="text-xl font-semibold">{title}</h1>
            {subtitle && (
              <p className="text-sm text-muted-foreground">{subtitle}</p>
            )}
          </div>
        </div>

        {/* Toolbar */}
        {config.showToolbar && (
          <div className="flex items-center space-x-2">
            {config.enableSearch && (
              <div className="relative">
                <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
                <Input
                  placeholder="Search nodes..."
                  value={interactionState.searchTerm}
                  onChange={(e) => handleSearch(e.target.value)}
                  className="pl-9 w-48"
                />
              </div>
            )}

            <Button variant="outline" size="sm" onClick={handleZoomIn}>
              <ZoomIn className="h-4 w-4" />
            </Button>
            <Button variant="outline" size="sm" onClick={handleZoomOut}>
              <ZoomOut className="h-4 w-4" />
            </Button>
            <Button variant="outline" size="sm" onClick={handleResetZoom}>
              <RotateCcw className="h-4 w-4" />
            </Button>
            <Button variant="outline" size="sm" onClick={handleDownload}>
              <Download className="h-4 w-4" />
            </Button>
          </div>
        )}
      </div>

      {/* Main content */}
      <div className="flex flex-1 overflow-hidden">
        {/* Graph container */}
        <div className="flex-1 relative">
          <div
            ref={containerRef}
            className="w-full h-full"
            style={{ minHeight: "400px" }}
          >
            {/* Cytoscape container - no SVG needed */}
          </div>
        </div>

        {/* Sidebar */}
        {config.showSidebar && (
          <div className="w-96 border-l bg-gray-50 overflow-y-auto">
            <div className="p-4 space-y-4">
              {/* Statistics */}
              {config.showStats && (
                <Card>
                  <CardHeader>
                    <CardTitle className="text-sm">Graph Overview</CardTitle>
                  </CardHeader>
                  <CardContent className="space-y-2">
                    <div className="flex justify-between">
                      <span className="text-sm text-muted-foreground">
                        Nodes:
                      </span>
                      <Badge variant="secondary">{stats.nodeCount}</Badge>
                    </div>
                    <div className="flex justify-between">
                      <span className="text-sm text-muted-foreground">
                        Links:
                      </span>
                      <Badge variant="secondary">{stats.linkCount}</Badge>
                    </div>
                    <div className="flex justify-between">
                      <span className="text-sm text-muted-foreground">
                        Avg Degree:
                      </span>
                      <Badge variant="outline">{stats.averageDegree}</Badge>
                    </div>
                  </CardContent>
                </Card>
              )}

              {/* Node Types */}
              {Object.keys(stats.nodeTypes).length > 0 && (
                <Card>
                  <CardHeader>
                    <CardTitle className="text-sm">Node Types</CardTitle>
                  </CardHeader>
                  <CardContent>
                    <div className="space-y-2">
                      {Object.entries(stats.nodeTypes).map(([type, count]) => (
                        <div
                          key={type}
                          className="flex justify-between items-center"
                        >
                          <span className="text-sm">{type}</span>
                          <Badge variant="outline">{count}</Badge>
                        </div>
                      ))}
                    </div>
                  </CardContent>
                </Card>
              )}

              {/* Selected Element Info */}
              {interactionState.selectedElement && (
                <Card>
                  <CardHeader>
                    <CardTitle className="text-sm">
                      {interactionState.selectedElementType === "node"
                        ? "Node"
                        : "Link"}{" "}
                      Details
                    </CardTitle>
                  </CardHeader>
                  <CardContent>
                    <div className="space-y-2">
                      <div>
                        <span className="text-sm font-medium">ID:</span>
                        <p className="text-sm text-muted-foreground break-all">
                          {interactionState.selectedElement.id}
                        </p>
                      </div>

                      {/* Show name only for nodes or links that have name/label */}
                      {interactionState.selectedElementType === "node" &&
                        (interactionState.selectedElement as UniversalNode)
                          .name && (
                          <div>
                            <span className="text-sm font-medium">Name:</span>
                            <p className="text-sm text-muted-foreground">
                              {
                                (
                                  interactionState.selectedElement as UniversalNode
                                ).name
                              }
                            </p>
                          </div>
                        )}

                      {interactionState.selectedElement.type && (
                        <div>
                          <span className="text-sm font-medium">Type:</span>
                          <Badge variant="secondary" className="ml-2">
                            {interactionState.selectedElement.type}
                          </Badge>
                        </div>
                      )}

                      {/* Link-specific info */}
                      {interactionState.selectedElementType === "link" && (
                        <>
                          <Separator />
                          <div>
                            <span className="text-sm font-medium">Source:</span>
                            <p className="text-sm text-muted-foreground">
                              {(() => {
                                const link =
                                  interactionState.selectedElement as UniversalLink;
                                return typeof link.source === "string"
                                  ? link.source
                                  : link.source.id;
                              })()}
                            </p>
                          </div>
                          <div>
                            <span className="text-sm font-medium">Target:</span>
                            <p className="text-sm text-muted-foreground">
                              {(() => {
                                const link =
                                  interactionState.selectedElement as UniversalLink;
                                return typeof link.target === "string"
                                  ? link.target
                                  : link.target.id;
                              })()}
                            </p>
                          </div>
                        </>
                      )}
                    </div>
                  </CardContent>
                </Card>
              )}

              {/* Custom children content */}
              {children}
            </div>
          </div>
        )}
      </div>
    </div>
  );
};
