"use client";

/**
 * Corpus graph orchestrator. Owns filter + selection state, decides whether to
 * render the full graph or a focused node neighborhood (the Obsidian "local
 * graph"), and wires the filter sidebar, canvas, and node detail panel.
 */

import { useEffect, useMemo, useState } from "react";

import { Button } from "@/components/ui/button";
import {
  type CorpusGraph,
  type GraphNode,
  useCorpusGraph,
  useGraphFacets,
  useNodeNeighborhood,
} from "@/lib/api/graph";
import {
  type GraphControls,
  GraphFilterPanel,
} from "@/components/graph/graph-filter-panel";
import { GraphCanvas } from "@/components/graph/graph-canvas";
import { GraphNodePanel } from "@/components/graph/graph-node-panel";

const NODE_LIMIT = 400;

function useDebouncedValue<T>(value: T, ms: number): T {
  const [debounced, setDebounced] = useState(value);
  useEffect(() => {
    const id = setTimeout(() => setDebounced(value), ms);
    return () => clearTimeout(id);
  }, [value, ms]);
  return debounced;
}

export function GraphView() {
  const [controls, setControls] = useState<GraphControls>({
    practiceArea: "",
    source: "",
    minCitations: 0,
    q: "",
    court: "",
    precedentLevel: "",
    chair: "",
    district: "",
    yearFrom: 0,
    yearTo: 0,
    showTopics: true,
    showPracticeAreas: true,
    showHalachot: false,
  });
  const facets = useGraphFacets().data;
  const [selectedNode, setSelectedNode] = useState<GraphNode | null>(null);
  const [focusNodeId, setFocusNodeId] = useState<string | null>(null);

  const onChange = (patch: Partial<GraphControls>) =>
    setControls((c) => ({ ...c, ...patch }));

  const nodeTypes = useMemo(() => {
    const t = ["precedent"];
    if (controls.showTopics) t.push("topic");
    if (controls.showPracticeAreas) t.push("practice_area");
    if (controls.showHalachot) t.push("halacha");
    return t.join(",");
  }, [controls.showTopics, controls.showPracticeAreas, controls.showHalachot]);

  const debouncedQ = useDebouncedValue(controls.q, 350);

  const filters = useMemo(
    () => ({
      practice_area: controls.practiceArea,
      source: controls.source,
      min_citations: controls.minCitations,
      node_types: nodeTypes,
      limit: NODE_LIMIT,
      q: debouncedQ,
      court: controls.court,
      precedent_level: controls.precedentLevel,
      chair: controls.chair,
      district: controls.district,
      year_from: controls.yearFrom,
      year_to: controls.yearTo,
    }),
    [
      controls.practiceArea,
      controls.source,
      controls.minCitations,
      controls.court,
      controls.precedentLevel,
      controls.chair,
      controls.district,
      controls.yearFrom,
      controls.yearTo,
      nodeTypes,
      debouncedQ,
    ],
  );

  const isFocused = !!focusNodeId;
  const full = useCorpusGraph(filters, !isFocused);
  const neighborhood = useNodeNeighborhood(focusNodeId, 1, nodeTypes);

  const active = isFocused ? neighborhood : full;
  const data: CorpusGraph | undefined = active.data;
  const error = active.error as Error | undefined;

  const handleNodeClick = (node: GraphNode) => {
    setSelectedNode(node);
    setFocusNodeId(node.id);
  };

  const backToFull = () => {
    setFocusNodeId(null);
    setSelectedNode(null);
  };

  return (
    <div className="space-y-3">
      <div className="flex items-center justify-between gap-3 text-xs text-ink-muted">
        <span>
          {data
            ? `${data.nodes.length} נקודות · ${data.edges.length} קשרים`
            : "—"}
        </span>
        {!isFocused && full.data?.truncated && (
          <span className="text-gold-deep">
            מוצגות {full.data.nodes.length} הנקודות המצוטטות ביותר מתוך{" "}
            {full.data.total_available} — צמצמו את הסינון כדי לראות פחות
          </span>
        )}
      </div>

      <div className="flex gap-4 h-[calc(100vh-320px)] min-h-[560px]">
        <GraphFilterPanel controls={controls} onChange={onChange} facets={facets} />

        <div className="relative flex-1 rounded-lg border border-rule bg-surface overflow-hidden">
          {error ? (
            <div className="grid h-full place-items-center p-6 text-center">
              <div className="space-y-2">
                <p className="text-red-700 font-medium m-0">שגיאה בטעינת הגרף</p>
                <p className="text-ink-muted text-sm m-0">{error.message}</p>
                <Button variant="outline" size="sm" onClick={() => active.refetch()}>
                  נסה שוב
                </Button>
              </div>
            </div>
          ) : active.isLoading && !data ? (
            <div className="grid h-full place-items-center text-sm text-ink-muted">
              טוען גרף…
            </div>
          ) : data && data.nodes.length === 0 ? (
            <div className="grid h-full place-items-center text-sm text-ink-muted">
              אין נקודות התואמות לסינון.
            </div>
          ) : (
            <GraphCanvas
              data={data}
              selectedId={selectedNode?.id ?? null}
              onNodeClick={handleNodeClick}
            />
          )}

          {isFocused && (
            <Button
              variant="outline"
              size="sm"
              onClick={backToFull}
              className="absolute top-3 start-3 bg-surface/90 backdrop-blur"
            >
              ← חזרה לגרף המלא
            </Button>
          )}

          <Legend />
        </div>

        {selectedNode && (
          <GraphNodePanel node={selectedNode} onClose={() => setSelectedNode(null)} />
        )}
      </div>
    </div>
  );
}

function Legend() {
  const items = [
    { color: "#1e3a5f", label: "פסיקה" },
    { color: "#a97d3a", label: "נושא" },
    { color: "#475569", label: "תחום" },
  ];
  return (
    <div className="absolute bottom-3 end-3 flex flex-col gap-1 rounded-md bg-surface/85 backdrop-blur px-3 py-2 text-xs text-ink-muted">
      {items.map((i) => (
        <div key={i.label} className="flex items-center gap-2">
          <span
            className="inline-block size-2.5 rounded-full"
            style={{ backgroundColor: i.color }}
          />
          {i.label}
        </div>
      ))}
    </div>
  );
}
