"use client";

import "@xyflow/react/dist/style.css";

import {
  Background,
  BackgroundVariant,
  Controls,
  MiniMap,
  ReactFlow,
  ReactFlowProvider,
  useEdgesState,
  useNodesState,
  useReactFlow,
  type Edge,
} from "@xyflow/react";
import { useEffect, useMemo } from "react";
import { collectVisible, layoutWithDagre } from "./graphLayout";
import { OrgChartNode, type OrgChartRFNode } from "./OrgChartNode";
import type { ChartNode, ChartNodeKind } from "./types";

// Referentially stable across renders — React Flow treats a new nodeTypes
// object as a change and remounts every custom node otherwise.
const NODE_TYPES = { orgNode: OrgChartNode };

const MINIMAP_COLORS: Record<ChartNodeKind, string> = {
  person: "#d6046e",
  role: "#5c2e91",
  group: "#c9b3c0",
  vacancy: "#f6cfe2",
};

export type GraphOrgChartProps = {
  tree: ChartNode[];
  isExpanded: (id: string) => boolean;
  onToggle: (id: string) => void;
  matchedIds?: Set<string> | null;
};

export function GraphOrgChart(props: GraphOrgChartProps) {
  return (
    <ReactFlowProvider>
      <GraphOrgChartInner {...props} />
    </ReactFlowProvider>
  );
}

function GraphOrgChartInner({ tree, isExpanded, onToggle, matchedIds }: GraphOrgChartProps) {
  const { visibleNodes, visibleEdges } = useMemo(() => collectVisible(tree, isExpanded), [tree, isExpanded]);

  const { rfNodes, rfEdges } = useMemo(() => {
    const positions = layoutWithDagre(visibleNodes, visibleEdges);
    const rfNodes: OrgChartRFNode[] = visibleNodes.map((n) => ({
      id: n.id,
      type: "orgNode",
      position: positions.get(n.id) ?? { x: 0, y: 0 },
      draggable: false,
      data: {
        chartNode: n,
        expanded: n.children.length > 0 && isExpanded(n.id),
        hasChildren: n.children.length > 0,
        childCount: n.children.length,
        onToggle,
      },
    }));
    const rfEdges: Edge[] = visibleEdges.map((e) => ({
      id: e.id,
      source: e.source,
      target: e.target,
      type: "smoothstep",
      pathOptions: { borderRadius: 14 },
      style: { stroke: "#e3cddb", strokeWidth: 1.5 },
    }));
    return { rfNodes, rfEdges };
  }, [visibleNodes, visibleEdges, isExpanded, onToggle]);

  const [nodes, setNodes, onNodesChange] = useNodesState(rfNodes);
  const [edges, setEdges, onEdgesChange] = useEdgesState(rfEdges);
  const { fitView } = useReactFlow();

  useEffect(() => {
    setNodes(rfNodes);
    setEdges(rfEdges);
    const raf = requestAnimationFrame(() => fitView({ padding: 0.2, duration: 300 }));
    return () => cancelAnimationFrame(raf);
  }, [rfNodes, rfEdges, setNodes, setEdges, fitView]);

  useEffect(() => {
    if (!matchedIds || matchedIds.size === 0) return;
    const t = setTimeout(() => {
      const ids = [...matchedIds].filter((id) => visibleNodes.some((n) => n.id === id));
      if (ids.length > 0) fitView({ nodes: ids.map((id) => ({ id })), padding: 0.3, duration: 400 });
    }, 150);
    return () => clearTimeout(t);
  }, [matchedIds, visibleNodes, fitView]);

  return (
    // dvh, not vh: on iOS/Android the browser chrome collapses on scroll, and
    // vh is measured against the *expanded* viewport — the canvas would hang
    // off the bottom of the screen for as long as the toolbar is showing.
    <div className="orgchart-canvas h-[70dvh] min-h-[420px] w-full overflow-hidden rounded-lg border border-border bg-white">
      <ReactFlow
        nodes={nodes}
        edges={edges}
        onNodesChange={onNodesChange}
        onEdgesChange={onEdgesChange}
        nodeTypes={NODE_TYPES}
        nodesDraggable={false}
        nodesConnectable={false}
        edgesFocusable={false}
        // Deliberately NOT elementsSelectable={false}: React Flow computes
        // `hasPointerEvents = isSelectable || isDraggable || onClick || …`
        // and sets pointer-events:none on the node wrapper when all of them
        // are off — which kills the expand button and the name link inside
        // the card. Selection stays on and is just styled away in CSS.
        minZoom={0.1}
        maxZoom={1.75}
        fitView
        fitViewOptions={{ padding: 0.2 }}
      >
        <Background variant={BackgroundVariant.Dots} gap={22} size={1.4} color="#eedde6" />
        <Controls showInteractive={false} />
        {/* Hidden under lg via CSS: on a phone it would cover a real
            fraction of the canvas for little navigational benefit. */}
        <MiniMap
          pannable
          zoomable
          ariaLabel="Übersichtskarte"
          maskColor="rgba(249, 241, 245, 0.75)"
          nodeColor={(n) => MINIMAP_COLORS[(n.data as OrgChartNodeDataLike).chartNode.kind] ?? "#d6046e"}
          nodeStrokeWidth={0}
          nodeBorderRadius={3}
        />
      </ReactFlow>
    </div>
  );
}

type OrgChartNodeDataLike = { chartNode: { kind: ChartNodeKind } };
