import {
  useState,
  useCallback,
  useEffect,
  useMemo,
  useRef,
  type ReactNode,
} from "react";
import {
  createFileRoute,
  Link,
  redirect,
  useNavigate,
  useSearch,
} from "@tanstack/react-router";
import { useQuery, useClient } from "urql";
import { type ColumnDef } from "@tanstack/react-table";
import {
  AlertTriangle,
  History,
  Loader2,
  Search,
  Sparkles,
  X,
} from "lucide-react";
import {
  AgentsListQuery,
  TenantMembersListQuery,
  RecentWikiPagesQuery,
  WikiCompileJobsAdminQuery,
  WikiSearchQuery,
} from "@/lib/graphql-queries";
import {
  WikiGraph,
  type WikiGraphHandle,
  type WikiGraphNode,
  PAGE_TYPE_BADGE_CLASSES,
  pageTypeLabel,
  type WikiPageType,
} from "@thinkwork/graph";
import {
  WikiPageSheet,
  type WikiPageSheetEdge,
} from "@/components/WikiPageSheet";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
import { useTenant } from "@/context/TenantContext";
import { useBreadcrumbs } from "@/context/BreadcrumbContext";
import { PageSkeleton } from "@/components/PageSkeleton";
import { DataTable } from "@/components/ui/data-table";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  Sheet,
  SheetContent,
  SheetDescription,
  SheetHeader,
  SheetTitle,
} from "@/components/ui/sheet";
import { compileJobGateCounts } from "./-compile-job-gate-counts";

type WikiView = "pages" | "graph";

function isWikiView(v: unknown): v is WikiView {
  return v === "pages" || v === "graph";
}

export const Route = createFileRoute("/_authed/_tenant/wiki/")({
  beforeLoad: ({ search }) => {
    throw redirect({
      to: "/knowledge/wiki",
      search: search as any,
      replace: true,
    });
  },
  component: WikiPage,
  validateSearch: (
    search: Record<string, unknown>,
  ): { agent?: string; view?: WikiView } => ({
    ...(typeof search.agent === "string" && search.agent
      ? { agent: search.agent }
      : {}),
    ...(isWikiView(search.view) ? { view: search.view } : {}),
  }),
});

type WikiPageProps = {
  routeBase?: "/wiki" | "/knowledge/wiki";
  embedded?: boolean;
  breadcrumbs?: Parameters<typeof useBreadcrumbs>[0];
  onHeaderActionChange?: (action: ReactNode | null) => void;
};

type WikiRow = {
  id: string;
  type: WikiPageType;
  entitySubtype: string | null;
  displayType: string;
  slug: string;
  title: string;
  summary: string | null;
  lastCompiledAt: string | null;
  updatedAt: string | null;
  userId: string;
  agentId: string;
  agentName: string;
};

type UserScope = {
  userId: string;
  label: string;
  agentIds: string[];
};

type CompileJobRow = {
  id: string;
  status: string;
  trigger: string;
  attempt: number;
  startedAt?: string | null;
  finishedAt?: string | null;
  createdAt: string;
  error?: string | null;
  metrics?: unknown;
};

const EMPTY_COMPILE_JOBS: CompileJobRow[] = [];

function agentUserId(agent: any): string | null {
  return agent.humanPairId ?? agent.humanPair?.id ?? null;
}

function agentUserLabel(agent: any): string {
  return agent.humanPair?.name ?? agent.humanPair?.email ?? agent.name;
}

function PageTypeBadge({
  type,
  displayType,
}: {
  type: WikiPageType;
  displayType: string;
}) {
  return (
    <Badge
      className={`font-normal text-xs ${
        PAGE_TYPE_BADGE_CLASSES[type] ?? "bg-muted text-muted-foreground"
      }`}
    >
      {displayType || pageTypeLabel(type)}
    </Badge>
  );
}

function latestJobTimestamp(job: CompileJobRow): string {
  return job.finishedAt ?? job.startedAt ?? job.createdAt;
}

function formatCompactDateTime(value?: string | null): string {
  if (!value) return "\u2014";
  return new Date(value).toLocaleString("en-US", {
    month: "short",
    day: "numeric",
    hour: "numeric",
    minute: "2-digit",
  });
}

function LatestRunButton({
  error,
  jobs,
  onClick,
}: {
  error?: { message?: string } | null;
  jobs: CompileJobRow[];
  onClick: () => void;
}) {
  const latest = jobs[0] ?? null;
  const counts = compileJobGateCounts(latest?.metrics);
  const hasRejected = counts.rejected > 0 || counts.unresolved > 0;
  const label = error ? "Run unavailable" : latest ? latest.status : "No runs";
  return (
    <Button
      type="button"
      variant="outline"
      size="sm"
      onClick={onClick}
      className="gap-2"
    >
      {hasRejected ? (
        <AlertTriangle className="h-3.5 w-3.5 text-amber-600" />
      ) : (
        <History className="h-3.5 w-3.5" />
      )}
      <span>Last run</span>
      <span className="text-muted-foreground">{label}</span>
    </Button>
  );
}

function CompileJobRunSheet({
  error,
  jobs,
}: {
  error?: { message?: string } | null;
  jobs: CompileJobRow[];
}) {
  const latest = jobs[0] ?? null;
  const counts = compileJobGateCounts(latest?.metrics);
  const hasRejected = counts.rejected > 0 || counts.unresolved > 0;
  return (
    <div className="flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto px-4 pb-4">
      <div className="rounded-md border border-border p-3">
        <p className="text-xs font-medium text-muted-foreground">
          Latest compile
        </p>
        <div className="mt-2 flex items-start justify-between gap-3">
          <div>
            <p className="text-sm font-medium">
              {error ? "Unavailable" : latest ? latest.status : "No jobs"}
            </p>
            <p className="mt-1 text-xs text-muted-foreground">
              {error
                ? "Could not load compile job status"
                : latest
                  ? `${latest.trigger} - ${formatCompactDateTime(latestJobTimestamp(latest))}`
                  : "No compile activity yet"}
            </p>
          </div>
          {hasRejected && (
            <Badge
              variant="outline"
              className="gap-1 border-amber-500/50 text-amber-700"
            >
              <AlertTriangle className="h-3.5 w-3.5" />
              Review
            </Badge>
          )}
        </div>
      </div>
      <div className="grid grid-cols-2 gap-2 sm:grid-cols-4">
        <MetricTile label="Approved" value={counts.approved} />
        <MetricTile label="Rejected" value={counts.rejected} />
        <MetricTile label="Unresolved" value={counts.unresolved} />
        <MetricTile label="Brain" value={counts.brainPages} />
      </div>
      {hasRejected && (
        <Button asChild variant="outline" size="sm" className="justify-start">
          <Link to="/ontology">Open ontology suggestions</Link>
        </Button>
      )}
      <div className="space-y-2">
        <p className="text-xs font-medium text-muted-foreground">Recent runs</p>
        {jobs.length === 0 ? (
          <p className="rounded-md border border-border p-3 text-sm text-muted-foreground">
            No compile jobs yet.
          </p>
        ) : (
          jobs.map((job) => (
            <div
              key={job.id}
              className="rounded-md border border-border p-3 text-sm"
            >
              <div className="flex items-center justify-between gap-3">
                <span className="font-medium">{job.status}</span>
                <span className="text-xs text-muted-foreground">
                  {job.trigger}
                </span>
              </div>
              <div className="mt-1 text-xs text-muted-foreground">
                {formatCompactDateTime(latestJobTimestamp(job))}
              </div>
              {job.error && (
                <p className="mt-2 text-xs text-destructive">{job.error}</p>
              )}
            </div>
          ))
        )}
      </div>
    </div>
  );
}

function MetricTile({ label, value }: { label: string; value: number }) {
  return (
    <div className="rounded-md border border-border p-3">
      <p className="text-xs font-medium text-muted-foreground">{label}</p>
      <p className="mt-1 text-lg font-semibold tabular-nums">{value}</p>
    </div>
  );
}

export function WikiPage({
  routeBase = "/wiki",
  embedded = false,
  breadcrumbs = [{ label: "Wiki Pages" }],
  onHeaderActionChange,
}: WikiPageProps = {}) {
  const { tenantId } = useTenant();
  const { agent, view: viewParam } = useSearch({ strict: false }) as {
    agent?: string;
    view?: WikiView;
  };
  const navigate = useNavigate();
  const selectedAgentId = agent ?? "all";
  const view: WikiView = viewParam ?? "pages";
  const [searchQuery, setSearchQuery] = useState("");
  const [activeSearch, setActiveSearch] = useState("");
  const graphRef = useRef<WikiGraphHandle>(null);

  const updateFilters = useCallback(
    (next: { agent?: string; view?: WikiView }) => {
      navigate({
        to: routeBase,
        search: {
          ...(next.agent && next.agent !== "all" ? { agent: next.agent } : {}),
          ...(next.view && next.view !== "pages" ? { view: next.view } : {}),
        },
        replace: true,
      });
    },
    [navigate, routeBase],
  );
  const setSelectedAgentId = useCallback(
    (nextAgent: string) => updateFilters({ agent: nextAgent, view }),
    [updateFilters, view],
  );
  const setView = useCallback(
    (nextView: WikiView) =>
      updateFilters({ agent: selectedAgentId, view: nextView }),
    [updateFilters, selectedAgentId],
  );

  // List-row detail sheet
  const [sheetOpen, setSheetOpen] = useState(false);
  const [selectedRow, setSelectedRow] = useState<WikiRow | null>(null);
  const [compileSheetOpen, setCompileSheetOpen] = useState(false);

  // Graph-node detail sheet (separate state so user can toggle between
  // views without losing their place)
  const [graphNode, setGraphNode] = useState<WikiGraphNode | null>(null);
  const [graphNodeEdges, setGraphNodeEdges] = useState<WikiPageSheetEdge[]>([]);
  const [graphSheetOpen, setGraphSheetOpen] = useState(false);
  const [graphNodeHistory, setGraphNodeHistory] = useState<
    { node: WikiGraphNode; edges: WikiPageSheetEdge[] }[]
  >([]);

  const [agentsResult] = useQuery({
    query: AgentsListQuery,
    variables: { tenantId: tenantId ?? "" },
    pause: !tenantId,
  });
  const [membersResult] = useQuery({
    query: TenantMembersListQuery,
    variables: { tenantId: tenantId ?? "" },
    pause: !tenantId,
  });
  const [compileJobsResult] = useQuery({
    query: WikiCompileJobsAdminQuery,
    variables: { tenantId: tenantId ?? "", ownerId: null, limit: 5 },
    pause: !tenantId,
  });

  const agents = useMemo(
    () =>
      [...(agentsResult.data?.agents ?? [])].sort((a, b) =>
        a.name.localeCompare(b.name),
      ),
    [agentsResult.data],
  );

  const memberScopes = useMemo<UserScope[]>(() => {
    const members = membersResult.data?.tenantMembers ?? [];
    return members
      .filter((m) => m.principalType.toLowerCase() === "user" && m.user)
      .map((m) => ({
        userId: m.user!.id,
        label: m.user!.name ?? m.user!.email,
        agentIds: [],
      }))
      .sort((a, b) => a.label.localeCompare(b.label));
  }, [membersResult.data]);

  const userScopes = useMemo<UserScope[]>(() => {
    const map = new Map<string, UserScope>();
    for (const scope of memberScopes) {
      map.set(scope.userId, { ...scope, agentIds: [...scope.agentIds] });
    }
    for (const a of agents) {
      const userId = agentUserId(a);
      if (!userId) continue;
      const existing = map.get(userId);
      if (existing) {
        existing.agentIds.push(a.id);
        continue;
      }
      map.set(userId, {
        userId,
        label: agentUserLabel(a),
        agentIds: [a.id],
      });
    }
    return [...map.values()].sort((a, b) => a.label.localeCompare(b.label));
  }, [agents, memberScopes]);
  const userLabels = useMemo(() => {
    const map: Record<string, string> = {};
    for (const scope of userScopes) map[scope.userId] = scope.label;
    return map;
  }, [userScopes]);

  const isAllAgents = selectedAgentId === "all";
  const selectedScope = userScopes.find(
    (scope) =>
      scope.userId === selectedAgentId ||
      scope.agentIds.includes(selectedAgentId),
  );
  const selectedScopeId = isAllAgents
    ? "all"
    : (selectedScope?.userId ?? selectedAgentId);
  const effectiveUserId = isAllAgents
    ? userScopes[0]?.userId
    : selectedScope?.userId;
  const effectiveUserIds = useMemo(
    () => (isAllAgents ? userScopes.map((scope) => scope.userId) : []),
    [isAllAgents, userScopes],
  );

  // Single-user list
  const [listResult, refetchList] = useQuery({
    query: RecentWikiPagesQuery,
    variables: { userId: effectiveUserId ?? "" },
    pause: !!activeSearch || isAllAgents || !effectiveUserId,
  });

  // Multi-user list fan-out — same client.query pattern Memories
  // uses to dodge the resolver's "all" branch and to give each user their
  // own owner scope.
  const client = useClient();
  const [multiPages, setMultiPages] = useState<WikiRow[] | null>(null);
  const [multiFetching, setMultiFetching] = useState(false);

  const fetchAllAgentPages = useCallback(async () => {
    if (!isAllAgents || userScopes.length === 0 || activeSearch) return;
    setMultiFetching(true);
    try {
      const perAgent = await Promise.all(
        userScopes.map(async (scope) => {
          try {
            const res = await client
              .query(RecentWikiPagesQuery, { userId: scope.userId })
              .toPromise();
            const pages = res.data?.recentWikiPages ?? [];
            return pages.map((p: any) => toRow(p, scope.userId, scope.label));
          } catch {
            return [] as WikiRow[];
          }
        }),
      );
      setMultiPages(perAgent.flat());
    } finally {
      setMultiFetching(false);
    }
  }, [isAllAgents, userScopes, activeSearch, client]);

  useEffect(() => {
    if (isAllAgents && !activeSearch) {
      fetchAllAgentPages();
    } else {
      setMultiPages(null);
    }
  }, [isAllAgents, activeSearch, fetchAllAgentPages]);

  // Search — single user in v1. All-Users + search is deferred; we
  // fall back to the first user's scope so the user sees *something*
  // rather than an empty panel.
  const searchUserId = isAllAgents
    ? (userScopes[0]?.userId ?? "")
    : (effectiveUserId ?? "");
  const [searchResult] = useQuery({
    query: WikiSearchQuery,
    variables: {
      tenantId: tenantId ?? "",
      userId: searchUserId,
      query: activeSearch,
      limit: 50,
    },
    pause: !activeSearch || !tenantId || !searchUserId,
  });

  useBreadcrumbs(breadcrumbs);

  const toRow = (p: any, userId: string, userName: string): WikiRow => ({
    id: p.id,
    type: p.type as WikiPageType,
    entitySubtype: p.entitySubtype ?? null,
    displayType: p.displayType ?? pageTypeLabel(p.type),
    slug: p.slug,
    title: p.title,
    summary: p.summary ?? null,
    lastCompiledAt: p.lastCompiledAt ?? null,
    updatedAt: p.updatedAt ?? null,
    userId,
    agentId: userId,
    agentName: userName,
  });

  const rows: WikiRow[] = useMemo(() => {
    if (activeSearch) {
      const hits = searchResult.data?.wikiSearch ?? [];
      return hits.map((h: any) =>
        toRow(h.page, searchUserId, userLabels[searchUserId] ?? ""),
      );
    }
    if (isAllAgents) {
      return (multiPages ?? []).slice().sort((a, b) => {
        const da = a.lastCompiledAt ?? a.updatedAt ?? "";
        const db = b.lastCompiledAt ?? b.updatedAt ?? "";
        return db.localeCompare(da);
      });
    }
    const pages = listResult.data?.recentWikiPages ?? [];
    return pages.map((p: any) =>
      toRow(p, effectiveUserId ?? "", userLabels[effectiveUserId ?? ""] ?? ""),
    );
  }, [
    activeSearch,
    searchResult.data,
    isAllAgents,
    multiPages,
    listResult.data,
    effectiveUserId,
    searchUserId,
    userLabels,
  ]);
  const compileJobs = (compileJobsResult.data?.wikiCompileJobs ??
    EMPTY_COMPILE_JOBS) as CompileJobRow[];
  const latestCompileCounts = compileJobGateCounts(compileJobs[0]?.metrics);

  useEffect(() => {
    if (!onHeaderActionChange) return;

    onHeaderActionChange(
      <LatestRunButton
        error={compileJobsResult.error}
        jobs={compileJobs}
        onClick={() => setCompileSheetOpen(true)}
      />,
    );

    return () => onHeaderActionChange(null);
  }, [compileJobs, compileJobsResult.error, onHeaderActionChange]);

  const hasGateEvidenceWithoutPages =
    !activeSearch &&
    rows.length === 0 &&
    (latestCompileCounts.rejected > 0 || latestCompileCounts.unresolved > 0);

  const columns: ColumnDef<WikiRow>[] = [
    {
      accessorKey: "lastCompiledAt",
      header: "Date",
      size: 140,
      cell: ({ row }) => {
        const d = row.original.lastCompiledAt ?? row.original.updatedAt;
        return d
          ? new Date(d).toLocaleDateString("en-US", {
              month: "short",
              day: "numeric",
              hour: "numeric",
              minute: "2-digit",
            })
          : "\u2014";
      },
    },
    {
      accessorKey: "agentName",
      header: "User",
      size: 120,
      cell: ({ row }) => (
        <span className="text-muted-foreground text-xs">
          {row.original.agentName}
        </span>
      ),
    },
    {
      accessorKey: "type",
      header: "Type",
      size: 110,
      cell: ({ row }) => (
        <PageTypeBadge
          type={row.original.type}
          displayType={row.original.displayType}
        />
      ),
    },
    {
      accessorKey: "title",
      header: "Title",
      cell: ({ row }) => (
        <span className="font-medium truncate block">{row.original.title}</span>
      ),
    },
  ];

  const handleRowClick = useCallback((row: WikiRow) => {
    setSelectedRow(row);
    setSheetOpen(true);
  }, []);

  const handleSearch = () => {
    setActiveSearch(searchQuery.trim());
  };

  if (agentsResult.fetching && !agentsResult.data) return <PageSkeleton />;

  const isLoading = activeSearch
    ? searchResult.fetching && !searchResult.data
    : isAllAgents
      ? multiFetching && multiPages === null
      : listResult.fetching && !listResult.data;

  return (
    <div
      className={
        embedded
          ? "flex h-full min-w-0 flex-col"
          : "flex flex-col -m-6 h-[calc(100%+48px)] min-w-0"
      }
    >
      <div
        className={
          embedded
            ? "relative z-10 flex shrink-0 flex-wrap items-center justify-between gap-3 pb-3"
            : "relative z-10 flex shrink-0 flex-wrap items-center justify-between gap-3 px-4 pb-3"
        }
      >
        <div className="relative w-80 max-w-full">
          <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
          <Input
            placeholder="Search pages..."
            value={searchQuery}
            onChange={(e) => setSearchQuery(e.target.value)}
            onKeyDown={(e) => e.key === "Enter" && handleSearch()}
            className="pl-9"
          />
          {searchQuery && (
            <button
              onClick={() => {
                setSearchQuery("");
                setActiveSearch("");
              }}
              className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground"
            >
              <X className="h-3.5 w-3.5" />
            </button>
          )}
        </div>
        <div className="flex shrink-0 items-center gap-2">
          {!onHeaderActionChange && (
            <LatestRunButton
              error={compileJobsResult.error}
              jobs={compileJobs}
              onClick={() => setCompileSheetOpen(true)}
            />
          )}
          <ToggleGroup
            type="single"
            value={view}
            onValueChange={(v) => v && setView(v as "pages" | "graph")}
            variant="outline"
          >
            <ToggleGroupItem value="pages" className="px-3 text-xs">
              Table
            </ToggleGroupItem>
            <ToggleGroupItem value="graph" className="px-3 text-xs">
              Graph
            </ToggleGroupItem>
          </ToggleGroup>
          <Select value={selectedScopeId} onValueChange={setSelectedAgentId}>
            <SelectTrigger className="w-44">
              <SelectValue placeholder="Select user" />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="all">All Users</SelectItem>
              {userScopes.map((scope) => (
                <SelectItem key={scope.userId} value={scope.userId}>
                  {scope.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
      </div>

      <div className={embedded ? "min-h-0 flex-1" : "min-h-0 flex-1 px-4"}>
        {view === "graph" ? (
          <div className="h-full relative border border-border rounded-lg overflow-hidden">
            <WikiGraph
              ref={graphRef}
              tenantId={tenantId ?? ""}
              userId={isAllAgents ? undefined : effectiveUserId}
              userIds={isAllAgents ? effectiveUserIds : undefined}
              searchQuery={searchQuery || undefined}
              onNodeClick={(node, edges) => {
                setGraphNode(node);
                setGraphNodeEdges(edges);
                setGraphNodeHistory([]);
                setGraphSheetOpen(true);
              }}
            />
          </div>
        ) : isLoading ? (
          <div className="flex items-center justify-center gap-2 py-12 text-sm text-muted-foreground">
            <Loader2 className="h-4 w-4 animate-spin" /> Loading pages...
          </div>
        ) : rows.length === 0 ? (
          <div className="flex flex-col items-center gap-3 py-16 text-center">
            <Sparkles className="h-12 w-12 text-muted-foreground/40" />
            <p className="text-sm text-muted-foreground max-w-sm">
              {activeSearch
                ? "No pages match your search."
                : hasGateEvidenceWithoutPages
                  ? "Evidence exists, but the ontology gate did not find an approved type for a compiled page yet."
                  : "No compiled pages yet — ask an agent a few questions and come back in a few minutes."}
            </p>
            {hasGateEvidenceWithoutPages && (
              <Link
                to="/ontology"
                className="text-sm font-medium text-primary hover:underline"
              >
                Review ontology suggestions
              </Link>
            )}
          </div>
        ) : (
          <DataTable
            columns={columns}
            data={rows}
            onRowClick={handleRowClick}
            scrollable
            pageSize={25}
            tableClassName="table-fixed"
          />
        )}
      </div>

      <Sheet open={compileSheetOpen} onOpenChange={setCompileSheetOpen}>
        <SheetContent className="sm:max-w-xl">
          <SheetHeader>
            <SheetTitle>Last Wiki Run</SheetTitle>
            <SheetDescription>
              Compile status and ontology gate counts for recent Wiki jobs.
            </SheetDescription>
          </SheetHeader>
          <CompileJobRunSheet
            error={compileJobsResult.error}
            jobs={compileJobs}
          />
        </SheetContent>
      </Sheet>

      {/* List-row detail sheet */}
      <Sheet open={sheetOpen} onOpenChange={setSheetOpen}>
        <SheetContent className="sm:max-w-lg flex flex-col">
          {selectedRow && (
            <WikiPageSheet
              tenantId={tenantId ?? ""}
              userId={selectedRow.userId}
              type={selectedRow.type}
              slug={selectedRow.slug}
              title={selectedRow.title}
              displayType={selectedRow.displayType}
            />
          )}
        </SheetContent>
      </Sheet>

      {/* Graph-node detail sheet (with re-anchoring history) */}
      <Sheet open={graphSheetOpen} onOpenChange={setGraphSheetOpen}>
        <SheetContent className="sm:max-w-lg flex flex-col">
          {graphNode && (
            <WikiPageSheet
              tenantId={tenantId ?? ""}
              userId={graphNode.agentId}
              type={graphNode.entityType}
              slug={graphNode.slug}
              title={graphNode.label}
              displayType={graphNode.displayType ?? undefined}
              connectedEdges={graphNodeEdges}
              historyDepth={graphNodeHistory.length}
              onBack={() => {
                const prev = graphNodeHistory[graphNodeHistory.length - 1];
                if (!prev) return;
                setGraphNodeHistory((h) => h.slice(0, -1));
                setGraphNode(prev.node);
                setGraphNodeEdges(prev.edges);
              }}
              onEdgeClick={(edge) => {
                const result = graphRef.current?.getNodeWithEdges(
                  edge.targetId,
                );
                if (result && graphNode) {
                  setGraphNodeHistory((h) => [
                    ...h,
                    { node: graphNode, edges: graphNodeEdges },
                  ]);
                  setGraphNode(result.node);
                  setGraphNodeEdges(result.edges);
                }
              }}
            />
          )}
        </SheetContent>
      </Sheet>
    </div>
  );
}
