"use client";

import React, { useEffect, useMemo, useRef, useState } from "react";
import cytoscape, { Core } from "cytoscape";

type GraphNodeDTO = {
  id: string;
  label: string;
  sectors: string[];
  company: string | null;
  role: string | null;
};

type GraphEdgeDTO = {
  id: string;
  source: string;
  target: string;
  introducedByCount: number;
  hasProvenance: boolean;
};

type GraphData = {
  nodes: GraphNodeDTO[];
  edges: GraphEdgeDTO[];
};

type Props = {
  data: GraphData;
  height?: number | string;
};

export default function Graph({ data, height = 600 }: Props) {
  const containerRef = useRef<HTMLDivElement | null>(null);
  const cyRef = useRef<Core | null>(null);

  const [selectedNode, setSelectedNode] = useState<GraphNodeDTO | null>(null);
  const [selectedEdge, setSelectedEdge] = useState<GraphEdgeDTO | null>(null);

  const elements = useMemo(() => {
    const nodes = data.nodes.map((n) => ({
      data: {
        id: n.id,
        label: n.label,
        company: n.company,
        role: n.role,
        sectors: n.sectors,
      },
    }));
    const edges = data.edges.map((e) => ({
      data: {
        id: e.id,
        source: e.source,
        target: e.target,
        introducedByCount: e.introducedByCount,
        hasProvenance: e.hasProvenance,
      },
    }));
    return { nodes, edges };
  }, [data]);

  useEffect(() => {
    if (!containerRef.current) return;

    // Destroy previous instance if any
    if (cyRef.current) {
      cyRef.current.destroy();
      cyRef.current = null;
    }

    const cy = cytoscape({
      container: containerRef.current,
      elements: {
        nodes: elements.nodes,
        edges: elements.edges,
      },
      style: [
        {
          selector: "node",
          style: {
            "background-color": "#0ea5e9", // sky-500
            "border-width": 2,
            "border-color": "#0369a1", // sky-700
            label: "data(label)",
            "font-size": 10,
            "text-valign": "center",
            "text-halign": "center",
            color: "#111827", // gray-900
            "text-wrap": "wrap",
            "text-max-width": "90px",
          },
        },
        {
          selector: "edge",
          style: {
            width: 2,
            "line-color": "#94a3b8", // slate-400
            opacity: 0.9,
            "curve-style": "bezier",
          },
        },
        {
          selector: "edge[hasProvenance]",
          style: {
            "line-color": "#16a34a", // green-600
          },
        },
        {
          selector: ":selected",
          style: {
            "border-width": 3,
            "border-color": "#111827",
          },
        },
      ],
      layout: {
        name: "cose",
        animate: true,
        padding: 30,
      } as any,
      wheelSensitivity: 0.25,
    });

    // Fit initially
    cy.one("render", () => {
      cy.fit(undefined, 30);
    });

    // Handlers
    const onNodeSelect = (evt: any) => {
      const d = evt.target.data();
      setSelectedEdge(null);
      setSelectedNode({
        id: d.id,
        label: d.label,
        company: d.company ?? null,
        role: d.role ?? null,
        sectors: (d.sectors as string[]) ?? [],
      });
    };

    const onEdgeSelect = (evt: any) => {
      const d = evt.target.data();
      setSelectedNode(null);
      setSelectedEdge({
        id: d.id,
        source: d.source,
        target: d.target,
        introducedByCount: Number(d.introducedByCount ?? 0),
        hasProvenance: Boolean(d.hasProvenance),
      });
    };

    cy.on("tap", "node", onNodeSelect);
    cy.on("tap", "edge", onEdgeSelect);
    cy.on("tap", (evt) => {
      if (evt.target === cy) {
        setSelectedNode(null);
        setSelectedEdge(null);
      }
    });

    cyRef.current = cy;

    return () => {
      cy.off("tap", "node", onNodeSelect);
      cy.off("tap", "edge", onEdgeSelect);
      if (cyRef.current) {
        cyRef.current.destroy();
        cyRef.current = null;
      }
    };
  }, [elements]);

  const refit = () => {
    cyRef.current?.fit(undefined, 30);
  };

  const relayout = () => {
    if (!cyRef.current) return;
    const layout = cyRef.current.elements().layout({ name: "cose", animate: true, padding: 30 } as any);
    layout.run();
  };

  return (
    <div className="flex gap-4">
      <div className="flex-1 rounded border border-zinc-200 bg-white text-zinc-900 dark:text-zinc-900">
        <div className="flex items-center gap-2 border-b border-zinc-200 p-2">
          <span className="font-medium">Global Graph</span>
          <div className="ml-auto flex gap-2">
            <button
              onClick={refit}
              className="rounded border border-zinc-300 px-2 py-1 text-sm hover:bg-zinc-50"
              type="button"
            >
              Fit
            </button>
            <button
              onClick={relayout}
              className="rounded border border-zinc-300 px-2 py-1 text-sm hover:bg-zinc-50"
              type="button"
            >
              Layout
            </button>
          </div>
        </div>
        <div
          ref={containerRef}
          style={{ height, width: "100%" }}
          className="cytoscape-container"
        />
      </div>

      <div className="w-80 shrink-0 rounded border border-zinc-200 bg-white p-3 text-zinc-900 dark:text-zinc-900">
        <div className="mb-2 text-sm font-semibold">Details</div>
        {!selectedNode && !selectedEdge && (
          <div className="text-sm text-zinc-500">Tap a node or edge to see details.</div>
        )}

        {selectedNode && (
          <div className="space-y-2">
            <div>
              <div className="text-xs text-zinc-500">Person</div>
              <div className="font-medium">{selectedNode.label}</div>
            </div>
            {selectedNode.company || selectedNode.role ? (
              <div className="text-sm">
                {(selectedNode.role ?? "")} {selectedNode.company ? `@ ${selectedNode.company}` : ""}
              </div>
            ) : null}
            {selectedNode.sectors?.length ? (
              <div className="text-sm">
                <span className="text-xs text-zinc-500">Sectors:</span>{" "}
                {selectedNode.sectors.join(", ")}
              </div>
            ) : null}
          </div>
        )}

        {selectedEdge && (
          <div className="space-y-2">
            <div>
              <div className="text-xs text-zinc-500">Connection</div>
              <div className="text-sm">
                {selectedEdge.source} — {selectedEdge.target}
              </div>
            </div>
            <div className="text-sm">
              <span className="text-xs text-zinc-500">Provenance length:</span>{" "}
              {selectedEdge.introducedByCount}
            </div>
            <div className="text-sm">
              <span className="text-xs text-zinc-500">Has provenance:</span>{" "}
              {selectedEdge.hasProvenance ? "Yes" : "No"}
            </div>
          </div>
        )}
      </div>
    </div>
  );
}