"use client";

import { useEffect, useState, useCallback } from "react";
import { fetchEntryGraph } from "@/lib/api/knowledge";
import Link from "next/link";

interface GraphNode {
  id: string;
  slug: string;
  title: string;
  summary: string | null;
  tags: {
    id: string;
    name: string;
    slug: string;
    color: string | null;
  }[];
  depth: number;
}

interface GraphEdge {
  id: string;
  sourceId: string;
  targetId: string;
  linkText: string;
}

interface EntryGraphResponse {
  centerNode: GraphNode;
  nodes: GraphNode[];
  edges: GraphEdge[];
  stats: {
    totalNodes: number;
    totalEdges: number;
    maxDepth: number;
  };
}

interface EntryGraphViewerProps {
  slug: string;
  initialDepth?: number;
}

export function EntryGraphViewer({
  slug,
  initialDepth = 1,
}: EntryGraphViewerProps): React.JSX.Element {
  const [graphData, setGraphData] = useState<EntryGraphResponse | null>(null);
  const [depth, setDepth] = useState(initialDepth);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [selectedNode, setSelectedNode] = useState<GraphNode | null>(null);

  const loadGraph = useCallback(async () => {
    try {
      setIsLoading(true);
      setError(null);
      const data = await fetchEntryGraph(slug, depth);
      setGraphData(data as EntryGraphResponse);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to load graph");
    } finally {
      setIsLoading(false);
    }
  }, [slug, depth]);

  useEffect(() => {
    void loadGraph();
  }, [loadGraph]);

  const handleDepthChange = (newDepth: number): void => {
    setDepth(newDepth);
  };

  if (isLoading) {
    return (
      <div className="flex items-center justify-center p-12">
        <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500" />
      </div>
    );
  }

  if (error ?? !graphData) {
    return (
      <div className="p-8 text-center">
        <div className="text-red-500 mb-2">Error loading graph</div>
        <div className="text-sm text-gray-500 dark:text-gray-400">{error}</div>
      </div>
    );
  }

  const { centerNode, nodes, edges, stats } = graphData;

  // Group nodes by depth for better visualization
  const nodesByDepth = nodes.reduce<Record<number, GraphNode[]>>((acc, node) => {
    const d = node.depth;
    acc[d] ??= [];
    acc[d].push(node);
    return acc;
  }, {});

  return (
    <div className="flex flex-col h-full">
      {/* Toolbar */}
      <div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800">
        <div className="flex items-center gap-4">
          <h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100">Graph View</h2>
          <div className="text-sm text-gray-500 dark:text-gray-400">
            {stats.totalNodes} nodes • {stats.totalEdges} connections
          </div>
        </div>

        <div className="flex items-center gap-3">
          <label className="text-sm font-medium text-gray-700 dark:text-gray-300">Depth:</label>
          <div className="flex rounded-lg overflow-hidden border border-gray-200 dark:border-gray-700">
            {[1, 2, 3].map((d) => (
              <button
                key={d}
                onClick={() => {
                  handleDepthChange(d);
                }}
                className={`px-3 py-1.5 text-sm font-medium transition-colors ${
                  depth === d
                    ? "bg-blue-500 text-white"
                    : "bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700"
                }`}
              >
                {d}
              </button>
            ))}
          </div>
        </div>
      </div>

      {/* Graph Visualization - Simple List View */}
      <div className="flex-1 overflow-auto p-6">
        <div className="max-w-4xl mx-auto space-y-6">
          {/* Center Node */}
          <div className="text-center mb-8">
            <div className="inline-block">
              <NodeCard
                node={centerNode}
                isCenter
                onClick={() => {
                  setSelectedNode(centerNode);
                }}
                isSelected={selectedNode?.id === centerNode.id}
              />
            </div>
          </div>

          {/* Nodes by Depth */}
          {Object.entries(nodesByDepth)
            .filter(([d]) => d !== "0")
            .sort(([a], [b]) => Number(a) - Number(b))
            .map(([depthLevel, depthNodes]) => (
              <div key={depthLevel} className="space-y-3">
                <h3 className="text-sm font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wide">
                  Depth {depthLevel} ({depthNodes.length}{" "}
                  {depthNodes.length === 1 ? "node" : "nodes"})
                </h3>
                <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
                  {depthNodes.map((node) => (
                    <NodeCard
                      key={node.id}
                      node={node}
                      onClick={() => {
                        setSelectedNode(node);
                      }}
                      isSelected={selectedNode?.id === node.id}
                      connections={getNodeConnections(node.id, edges)}
                    />
                  ))}
                </div>
              </div>
            ))}
        </div>
      </div>

      {/* Selected Node Details */}
      {selectedNode && (
        <div className="border-t border-gray-200 dark:border-gray-700 p-4 bg-gray-50 dark:bg-gray-800">
          <div className="flex items-start justify-between max-w-4xl mx-auto">
            <div className="flex-1">
              <h3 className="font-semibold text-gray-900 dark:text-gray-100 text-lg">
                {selectedNode.title}
              </h3>
              {selectedNode.summary && (
                <p className="mt-2 text-sm text-gray-600 dark:text-gray-300">
                  {selectedNode.summary}
                </p>
              )}
              {selectedNode.tags.length > 0 && (
                <div className="flex flex-wrap gap-2 mt-3">
                  {selectedNode.tags.map((tag) => (
                    <span
                      key={tag.id}
                      className="inline-flex items-center px-2.5 py-0.5 rounded text-xs font-medium"
                      style={{
                        backgroundColor: tag.color ?? "#6B7280",
                        color: "#FFFFFF",
                      }}
                    >
                      {tag.name}
                    </span>
                  ))}
                </div>
              )}
              <div className="mt-4">
                <Link
                  href={`/knowledge/${selectedNode.slug}`}
                  className="text-sm text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300"
                >
                  View Full Entry →
                </Link>
              </div>
            </div>
            <button
              onClick={() => {
                setSelectedNode(null);
              }}
              className="ml-4 text-gray-400 hover:text-gray-600 dark:hover:text-gray-200"
            >
              <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  strokeWidth={2}
                  d="M6 18L18 6M6 6l12 12"
                />
              </svg>
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

interface NodeCardProps {
  node: GraphNode;
  isCenter?: boolean;
  onClick?: () => void;
  isSelected?: boolean;
  connections?: { incoming: number; outgoing: number };
}

function NodeCard({
  node,
  isCenter,
  onClick,
  isSelected,
  connections,
}: NodeCardProps): React.JSX.Element {
  return (
    <div
      onClick={onClick}
      className={`p-4 rounded-lg border-2 transition-all cursor-pointer ${
        isCenter
          ? "bg-blue-50 dark:bg-blue-900/20 border-blue-500 dark:border-blue-500"
          : isSelected
            ? "bg-gray-100 dark:bg-gray-700 border-blue-400 dark:border-blue-400"
            : "bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-700 hover:border-gray-300 dark:hover:border-gray-600"
      }`}
    >
      <div className="flex items-start justify-between">
        <div className="flex-1 min-w-0">
          <h4 className="font-medium text-gray-900 dark:text-gray-100 truncate">{node.title}</h4>
          {node.summary && (
            <p className="mt-1 text-sm text-gray-600 dark:text-gray-400 line-clamp-2">
              {node.summary}
            </p>
          )}
          {node.tags.length > 0 && (
            <div className="flex flex-wrap gap-1 mt-2">
              {node.tags.slice(0, 3).map((tag) => (
                <span
                  key={tag.id}
                  className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium"
                  style={{
                    backgroundColor: tag.color ?? "#6B7280",
                    color: "#FFFFFF",
                  }}
                >
                  {tag.name}
                </span>
              ))}
              {node.tags.length > 3 && (
                <span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-200 dark:bg-gray-600 text-gray-700 dark:text-gray-300">
                  +{node.tags.length - 3}
                </span>
              )}
            </div>
          )}
          {connections && (
            <div className="mt-2 text-xs text-gray-500 dark:text-gray-400">
              {connections.incoming} incoming • {connections.outgoing} outgoing
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

function getNodeConnections(
  nodeId: string,
  edges: GraphEdge[]
): { incoming: number; outgoing: number } {
  const incoming = edges.filter((e) => e.targetId === nodeId).length;
  const outgoing = edges.filter((e) => e.sourceId === nodeId).length;
  return { incoming, outgoing };
}
