import React, { useMemo } from "react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { useAgentGraph } from "@/context/AgentGraphContext";
import { Network, BarChart3, Target, Activity } from "lucide-react";

interface ConnectedComponent {
  id: number;
  nodeIds: string[];
  size: number;
  density: number;
  maxDegree: number;
  avgDegree: number;
}

interface DegreeDistribution {
  [degree: number]: {
    count: number;
    percentage: number;
    entityTypes: string[];
  };
}

interface StructuralPattern {
  type: "star" | "chain" | "cluster" | "hub" | "isolated";
  description: string;
  nodeIds: string[];
  centralNodeId?: string;
  score: number;
}

interface StructuralData {
  totalNodes: number;
  totalEdges: number;
  networkDensity: number;
  avgDegree: number;
  maxDegree: number;
  connectedComponents: ConnectedComponent[];
  degreeDistribution: DegreeDistribution;
  structuralPatterns: StructuralPattern[];
  networkHealth: number;
  isolatedNodes: string[];
}

export function StructuralConnectivityAnalysis() {
  const { state } = useAgentGraph();

  const structuralData = useMemo<StructuralData>(() => {
    const nodeMap = new Map<
      string,
      { id: string; type: string; name: string }
    >();
    const adjacencyList = new Map<string, Set<string>>();
    const edgeSet = new Set<string>();

    // Process all traces and their knowledge graphs
    state.traces.forEach((trace) => {
      trace.knowledge_graphs?.forEach((kg: any) => {
        if (kg.graph_data) {
          try {
            const graphData =
              typeof kg.graph_data === "string"
                ? JSON.parse(kg.graph_data)
                : kg.graph_data;

            // Build node map
            if (graphData.entities && Array.isArray(graphData.entities)) {
              graphData.entities.forEach((entity: any) => {
                nodeMap.set(entity.id, {
                  id: entity.id,
                  type: entity.type || "Unknown",
                  name: entity.name || entity.id,
                });
                adjacencyList.set(entity.id, new Set());
              });
            }

            // Build adjacency list and count edges
            if (graphData.relations && Array.isArray(graphData.relations)) {
              graphData.relations.forEach((relation: any) => {
                const sourceId = relation.source;
                const targetId = relation.target;
                const edgeKey = [sourceId, targetId].sort().join("-");

                if (
                  nodeMap.has(sourceId) &&
                  nodeMap.has(targetId) &&
                  !edgeSet.has(edgeKey)
                ) {
                  adjacencyList.get(sourceId)?.add(targetId);
                  adjacencyList.get(targetId)?.add(sourceId);
                  edgeSet.add(edgeKey);
                }
              });
            }
          } catch (error) {
            console.warn("Error parsing graph_data:", error);
          }
        }
      });
    });

    const totalNodes = nodeMap.size;
    const totalEdges = edgeSet.size;

    // Calculate basic metrics
    const networkDensity =
      totalNodes > 1 ? (2 * totalEdges) / (totalNodes * (totalNodes - 1)) : 0;

    const degrees = Array.from(adjacencyList.values()).map(
      (neighbors) => neighbors.size
    );
    const avgDegree =
      degrees.length > 0
        ? Math.round(
            (degrees.reduce((sum, d) => sum + d, 0) / degrees.length) * 10
          ) / 10
        : 0;
    const maxDegree = Math.max(...degrees, 0);

    // Find connected components using DFS
    const visited = new Set<string>();
    const connectedComponents: ConnectedComponent[] = [];

    const dfs = (nodeId: string, component: string[]): void => {
      if (visited.has(nodeId)) return;
      visited.add(nodeId);
      component.push(nodeId);

      const neighbors = adjacencyList.get(nodeId) || new Set();
      neighbors.forEach((neighborId) => {
        if (!visited.has(neighborId)) {
          dfs(neighborId, component);
        }
      });
    };

    let componentId = 0;
    nodeMap.forEach((_, nodeId) => {
      if (!visited.has(nodeId)) {
        const component: string[] = [];
        dfs(nodeId, component);

        if (component.length > 0) {
          const componentEdges =
            component.reduce((count, nodeId) => {
              const neighbors = adjacencyList.get(nodeId) || new Set();
              const internalNeighbors = Array.from(neighbors).filter((n) =>
                component.includes(n)
              );
              return count + internalNeighbors.length;
            }, 0) / 2; // Divide by 2 since each edge is counted twice

          const componentDensity =
            component.length > 1
              ? (2 * componentEdges) /
                (component.length * (component.length - 1))
              : 0;

          const componentDegrees = component.map(
            (nodeId) => (adjacencyList.get(nodeId) || new Set()).size
          );

          connectedComponents.push({
            id: componentId++,
            nodeIds: component,
            size: component.length,
            density: Math.round(componentDensity * 1000) / 1000,
            maxDegree: Math.max(...componentDegrees, 0),
            avgDegree:
              componentDegrees.length > 0
                ? Math.round(
                    (componentDegrees.reduce((sum, d) => sum + d, 0) /
                      componentDegrees.length) *
                      10
                  ) / 10
                : 0,
          });
        }
      }
    });

    // Calculate degree distribution
    const degreeDistribution: DegreeDistribution = {};
    Array.from(nodeMap.entries()).forEach(([nodeId, node]) => {
      const degree = (adjacencyList.get(nodeId) || new Set()).size;
      if (!degreeDistribution[degree]) {
        degreeDistribution[degree] = {
          count: 0,
          percentage: 0,
          entityTypes: [],
        };
      }
      degreeDistribution[degree].count++;
      if (!degreeDistribution[degree].entityTypes.includes(node.type)) {
        degreeDistribution[degree].entityTypes.push(node.type);
      }
    });

    // Calculate percentages
    Object.values(degreeDistribution).forEach((dist) => {
      dist.percentage =
        totalNodes > 0 ? Math.round((dist.count / totalNodes) * 100) : 0;
    });

    // Identify structural patterns
    const structuralPatterns: StructuralPattern[] = [];

    // Find star patterns (one central node with many connections, others mostly connected to center)
    Array.from(nodeMap.keys()).forEach((nodeId) => {
      const neighbors = adjacencyList.get(nodeId) || new Set();
      if (neighbors.size >= 3) {
        // Check if this is a potential star center
        const neighborDegrees = Array.from(neighbors).map(
          (nId) => (adjacencyList.get(nId) || new Set()).size
        );
        const avgNeighborDegree =
          neighborDegrees.reduce((sum, d) => sum + d, 0) /
          neighborDegrees.length;

        if (neighbors.size >= avgNeighborDegree * 1.5) {
          structuralPatterns.push({
            type: "star",
            description: `Star pattern centered on ${
              nodeMap.get(nodeId)?.name
            }`,
            nodeIds: [nodeId, ...Array.from(neighbors)],
            centralNodeId: nodeId,
            score: neighbors.size,
          });
        }
      }
    });

    // Find hub patterns (nodes with significantly higher degree than average)
    const degreeThreshold = avgDegree * 2;
    Array.from(nodeMap.keys()).forEach((nodeId) => {
      const degree = (adjacencyList.get(nodeId) || new Set()).size;
      if (degree >= degreeThreshold && degree >= 4) {
        structuralPatterns.push({
          type: "hub",
          description: `High-degree hub: ${nodeMap.get(nodeId)?.name}`,
          nodeIds: [nodeId],
          centralNodeId: nodeId,
          score: degree,
        });
      }
    });

    // Find chain patterns (nodes with degree 2 in sequence)
    const visited_chains = new Set<string>();
    Array.from(nodeMap.keys()).forEach((nodeId) => {
      if (visited_chains.has(nodeId)) return;

      const neighbors = adjacencyList.get(nodeId) || new Set();
      if (neighbors.size === 2) {
        // Start building a chain
        const chain = [nodeId];
        visited_chains.add(nodeId);

        let current: string = nodeId;
        let prev: string | null = null;

        // Follow the chain
        let maxChainLength = 50; // Prevent infinite loops
        while (maxChainLength-- > 0) {
          const currentNeighbors = Array.from(
            adjacencyList.get(current) || new Set<string>()
          );
          const next = currentNeighbors.find((n: string) => n !== prev);

          if (!next || visited_chains.has(next)) break;

          const nextNeighbors = adjacencyList.get(next) || new Set();
          if (nextNeighbors.size > 2) break; // End of chain

          chain.push(next);
          visited_chains.add(next);
          prev = current;
          current = next;

          if (nextNeighbors.size === 1) break; // End node
        }

        if (chain.length >= 3) {
          structuralPatterns.push({
            type: "chain",
            description: `Chain of ${chain.length} nodes`,
            nodeIds: chain,
            score: chain.length,
          });
        }
      }
    });

    // Find isolated nodes
    const isolatedNodes = Array.from(nodeMap.keys()).filter(
      (nodeId) => (adjacencyList.get(nodeId) || new Set()).size === 0
    );

    // Calculate network health (0-100)
    const healthFactors = {
      connectivity:
        connectedComponents.length === 1
          ? 100
          : Math.max(0, 100 - connectedComponents.length * 10),
      isolation:
        isolatedNodes.length === 0
          ? 100
          : Math.max(0, 100 - isolatedNodes.length * 20),
      density: Math.min(100, networkDensity * 200), // Scale density to 0-100
      distribution:
        avgDegree > 0
          ? Math.min(100, (1 - (maxDegree - avgDegree) / maxDegree) * 100)
          : 100,
    };

    const networkHealth = Math.round(
      healthFactors.connectivity * 0.3 +
        healthFactors.isolation * 0.3 +
        healthFactors.density * 0.2 +
        healthFactors.distribution * 0.2
    );

    // Sort patterns by score
    structuralPatterns.sort((a, b) => b.score - a.score);

    return {
      totalNodes,
      totalEdges,
      networkDensity: Math.round(networkDensity * 1000) / 1000,
      avgDegree,
      maxDegree,
      connectedComponents: connectedComponents.sort((a, b) => b.size - a.size),
      degreeDistribution,
      structuralPatterns: structuralPatterns.slice(0, 6),
      networkHealth,
      isolatedNodes,
    };
  }, [state.traces]);

  const getHealthColor = (health: number) => {
    if (health >= 80) return "text-green-600";
    if (health >= 60) return "text-yellow-600";
    if (health >= 40) return "text-orange-600";
    return "text-red-600";
  };

  const getPatternColor = (type: string) => {
    const colorMap: { [key: string]: string } = {
      star: "bg-yellow-100 text-yellow-800 border-yellow-200",
      hub: "bg-red-100 text-red-800 border-red-200",
      chain: "bg-blue-100 text-blue-800 border-blue-200",
      cluster: "bg-green-100 text-green-800 border-green-200",
      isolated: "bg-gray-100 text-gray-800 border-gray-200",
    };
    return colorMap[type] || "bg-gray-100 text-gray-800 border-gray-200";
  };

  const getTypeColor = (index: number) => {
    const colors = [
      "bg-blue-500",
      "bg-green-500",
      "bg-yellow-500",
      "bg-purple-500",
      "bg-pink-500",
      "bg-indigo-500",
    ];
    return colors[index % colors.length];
  };

  if (structuralData.totalNodes === 0) {
    return (
      <Card>
        <CardHeader>
          <CardTitle className="flex items-center gap-2">
            <Network className="h-5 w-5" />
            Structural Connectivity Analysis
          </CardTitle>
        </CardHeader>
        <CardContent>
          <div className="text-center py-8 text-muted-foreground">
            <Network className="h-12 w-12 mx-auto mb-4 opacity-50" />
            <p>No structural data available</p>
            <p className="text-sm">
              Generate some knowledge graphs to see connectivity analysis
            </p>
          </div>
        </CardContent>
      </Card>
    );
  }

  return (
    <div className="space-y-6">
      {/* Summary Stats */}
      <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
        <Card>
          <CardContent className="p-4">
            <div className="flex items-center gap-3">
              <div className="p-2 rounded-lg bg-blue-100">
                <Network className="h-4 w-4 text-blue-600" />
              </div>
              <div>
                <p className="text-sm text-muted-foreground">Network Density</p>
                <p className="text-2xl font-bold">
                  {structuralData.networkDensity}
                </p>
              </div>
            </div>
          </CardContent>
        </Card>

        <Card>
          <CardContent className="p-4">
            <div className="flex items-center gap-3">
              <div className="p-2 rounded-lg bg-green-100">
                <Target className="h-4 w-4 text-green-600" />
              </div>
              <div>
                <p className="text-sm text-muted-foreground">Components</p>
                <p className="text-2xl font-bold">
                  {structuralData.connectedComponents.length}
                </p>
              </div>
            </div>
          </CardContent>
        </Card>

        <Card>
          <CardContent className="p-4">
            <div className="flex items-center gap-3">
              <div className="p-2 rounded-lg bg-purple-100">
                <BarChart3 className="h-4 w-4 text-purple-600" />
              </div>
              <div>
                <p className="text-sm text-muted-foreground">Avg Degree</p>
                <p className="text-2xl font-bold">{structuralData.avgDegree}</p>
              </div>
            </div>
          </CardContent>
        </Card>

        <Card>
          <CardContent className="p-4">
            <div className="flex items-center gap-3">
              <div className="p-2 rounded-lg bg-orange-100">
                <Activity className="h-4 w-4 text-orange-600" />
              </div>
              <div>
                <p className="text-sm text-muted-foreground">Network Health</p>
                <p
                  className={`text-2xl font-bold ${getHealthColor(
                    structuralData.networkHealth
                  )}`}
                >
                  {structuralData.networkHealth}%
                </p>
              </div>
            </div>
          </CardContent>
        </Card>
      </div>

      <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
        {/* Connected Components */}
        <Card>
          <CardHeader>
            <CardTitle className="flex items-center gap-2">
              <Target className="h-5 w-5" />
              Connected Components
            </CardTitle>
          </CardHeader>
          <CardContent>
            <div className="space-y-3">
              {structuralData.connectedComponents
                .slice(0, 6)
                .map((component, index) => (
                  <div
                    key={component.id}
                    className="flex items-center justify-between p-3 rounded-lg border"
                  >
                    <div className="flex items-center gap-3">
                      <div
                        className={`w-2 h-2 rounded-full ${getTypeColor(
                          index
                        )}`}
                      />
                      <div>
                        <p className="font-medium">
                          Component {component.id + 1}
                        </p>
                        <p className="text-sm text-muted-foreground">
                          {component.size} nodes • Density: {component.density}
                        </p>
                      </div>
                    </div>
                    <div className="flex items-center gap-2 flex-shrink-0">
                      <Badge variant="outline">
                        Max: {component.maxDegree}
                      </Badge>
                      <Badge variant="outline">
                        Avg: {component.avgDegree}
                      </Badge>
                    </div>
                  </div>
                ))}
              {structuralData.isolatedNodes.length > 0 && (
                <div className="flex items-center justify-between p-3 rounded-lg border border-dashed border-gray-300">
                  <div className="flex items-center gap-3">
                    <div className="w-2 h-2 rounded-full bg-gray-400" />
                    <div>
                      <p className="font-medium text-gray-600">
                        Isolated Nodes
                      </p>
                      <p className="text-sm text-muted-foreground">
                        {structuralData.isolatedNodes.length} disconnected nodes
                      </p>
                    </div>
                  </div>
                  <Badge className="bg-gray-100 text-gray-800 border-gray-200">
                    Isolated
                  </Badge>
                </div>
              )}
            </div>
          </CardContent>
        </Card>

        {/* Structural Patterns */}
        <Card>
          <CardHeader>
            <CardTitle className="flex items-center gap-2">
              <BarChart3 className="h-5 w-5" />
              Structural Patterns
            </CardTitle>
          </CardHeader>
          <CardContent>
            <div className="space-y-3">
              {structuralData.structuralPatterns.length > 0 ? (
                structuralData.structuralPatterns.map((pattern, index) => (
                  <div
                    key={index}
                    className="flex items-center justify-between p-3 rounded-lg border"
                  >
                    <div className="flex items-center gap-3">
                      <div
                        className={`w-2 h-2 rounded-full ${getTypeColor(
                          index
                        )}`}
                      />
                      <div>
                        <p className="font-medium capitalize">
                          {pattern.type} Pattern
                        </p>
                        <p
                          className="text-sm text-muted-foreground truncate"
                          title={pattern.description}
                        >
                          {pattern.description}
                        </p>
                      </div>
                    </div>
                    <div className="flex items-center gap-2 flex-shrink-0">
                      <Badge className={getPatternColor(pattern.type)}>
                        {pattern.type.toUpperCase()}
                      </Badge>
                      <Badge variant="outline">
                        {Math.round(pattern.score)}
                      </Badge>
                    </div>
                  </div>
                ))
              ) : (
                <div className="text-center py-4 text-muted-foreground">
                  <p className="text-sm">No significant patterns detected</p>
                </div>
              )}
            </div>
          </CardContent>
        </Card>
      </div>

      {/* Degree Distribution */}
      <Card>
        <CardHeader>
          <CardTitle className="flex items-center gap-2">
            <Activity className="h-5 w-5" />
            Degree Distribution
          </CardTitle>
        </CardHeader>
        <CardContent>
          <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
            {Object.entries(structuralData.degreeDistribution)
              .sort(([a], [b]) => parseInt(a) - parseInt(b))
              .slice(0, 8)
              .map(([degree, stats], index) => (
                <div key={degree} className="p-4 rounded-lg border">
                  <div className="flex items-center gap-2 mb-2">
                    <div
                      className={`w-3 h-3 rounded-full ${getTypeColor(index)}`}
                    />
                    <h4 className="font-medium">Degree {degree}</h4>
                  </div>
                  <div className="space-y-1 text-sm">
                    <div className="flex justify-between">
                      <span className="text-muted-foreground">Nodes:</span>
                      <span>{stats.count}</span>
                    </div>
                    <div className="flex justify-between">
                      <span className="text-muted-foreground">Percentage:</span>
                      <span>{stats.percentage}%</span>
                    </div>
                    <div className="mt-2">
                      <p className="text-muted-foreground text-xs mb-1">
                        Entity Types:
                      </p>
                      <div className="flex flex-wrap gap-1">
                        {stats.entityTypes
                          .slice(0, 3)
                          .map((type: string, _typeIndex: number) => (
                            <Badge
                              key={type}
                              variant="outline"
                              className="text-xs"
                            >
                              {type}
                            </Badge>
                          ))}
                        {stats.entityTypes.length > 3 && (
                          <Badge variant="outline" className="text-xs">
                            +{stats.entityTypes.length - 3}
                          </Badge>
                        )}
                      </div>
                    </div>
                  </div>
                </div>
              ))}
          </div>
        </CardContent>
      </Card>
    </div>
  );
}
