// Cinematic process graph. dagre auto-layout, animated active edge,
// glass nodes, minimap, selection ring.
import { useMemo, type ReactElement } from "react";
import ReactFlow, {
  Background, Controls, MiniMap, Handle, Position,
  type Edge, type Node, type NodeProps,
} from "reactflow";
import { useApp, scenarioById } from "../state/store";
import { layoutGraph, NODE_SIZE } from "../graph/layout";
import { Bot, User, Cog, Shield, Flag } from "./icons";
import type { ProcessStep, StepKind } from "../data/types";

type NodeData = ProcessStep & { selected: boolean };

const KIND_ICON: Record<StepKind, (p: { size?: number }) => ReactElement> = {
  start: Flag,
  end: Flag,
  human: User,
  agent: Bot,
  service: Cog,
  decision: Cog,
};

function StepNode({ data, id }: NodeProps<NodeData>) {
  const Icon = KIND_ICON[data.kind] ?? Cog;
  return (
    <div className={`node node-${data.state}${data.selected ? " node-sel" : ""}`} data-step={id}>
      <Handle type="target" position={Position.Left} className="node-handle" />
      <div className="node-row">
        <span className={`node-dot node-dot-${data.state}`} aria-hidden />
        <Icon size={13} />
        <span className="node-name">{data.name}</span>
      </div>
      <div className="node-meta">
        <span className={`node-kind node-kind-${data.kind}`}>{data.kind}</span>
        <span className="node-owner">{data.owner}</span>
        {data.governs.length > 0 && (
          <span className="node-gov"><Shield size={11} />{data.governs.length}</span>
        )}
      </div>
      <Handle type="source" position={Position.Right} className="node-handle" />
    </div>
  );
}

const nodeTypes = { step: StepNode };

const EDGE_COLOR: Record<string, string> = {
  done: "var(--ok)",
  running: "var(--run)",
  errored: "var(--block)",
  default: "var(--border-strong)",
};

export default function ProcessGraph() {
  const scenarioId = useApp((s) => s.scenarioId);
  const selectedStepId = useApp((s) => s.selectedStepId);
  const setSelectedStepId = useApp((s) => s.setSelectedStepId);

  const sc = scenarioById(scenarioId);

  const { nodes, edges } = useMemo(() => {
    if (!sc) return { nodes: [] as Node<NodeData>[], edges: [] as Edge[] };
    const positions = layoutGraph(sc.steps, sc.edges);
    const posById = new Map(positions.map((p) => [p.id, p.position]));
    const stepById = new Map(sc.steps.map((s) => [s.id, s]));
    const nodes: Node<NodeData>[] = sc.steps.map((s) => ({
      id: s.id,
      type: "step",
      position: posById.get(s.id) ?? { x: 0, y: 0 },
      data: { ...s, selected: s.id === selectedStepId },
    }));
    const edges: Edge[] = sc.edges.map((e) => {
      const srcStep = stepById.get(e.source);
      const isRunningEdge = srcStep?.state === "running";
      const color =
        srcStep?.state === "errored"
          ? EDGE_COLOR.errored
          : srcStep?.state === "done"
            ? EDGE_COLOR.done
            : srcStep?.state === "running"
              ? EDGE_COLOR.running
              : EDGE_COLOR.default;
      return {
        id: e.id,
        source: e.source,
        target: e.target,
        label: e.label,
        animated: isRunningEdge,
        type: "smoothstep",
        style: { stroke: color, strokeWidth: isRunningEdge ? 2.2 : 1.6, opacity: srcStep?.state === "idle" ? 0.55 : 1 },
        labelStyle: { fill: "var(--text-2)", fontSize: 11, fontFamily: "Fira Sans", fontWeight: 500 },
        labelBgPadding: [6, 4],
        labelBgBorderRadius: 4,
        labelBgStyle: { fill: "var(--surface)" },
      };
    });
    return { nodes, edges };
  }, [sc, selectedStepId]);

  if (!sc) return <div className="empty">No scenario loaded</div>;

  return (
    <div className="graph-canvas" data-anchor="graph">
      <ReactFlow
        nodes={nodes}
        edges={edges}
        nodeTypes={nodeTypes}
        onNodeClick={(_, n) => setSelectedStepId(n.id)}
        fitView
        fitViewOptions={{ padding: 0.2, minZoom: 0.75, maxZoom: 1 }}
        proOptions={{ hideAttribution: true }}
        minZoom={0.4}
        maxZoom={1.8}
        panOnScroll
        panOnDrag
        nodesDraggable={false}
        nodesConnectable={false}
        elementsSelectable
        defaultEdgeOptions={{ type: "smoothstep" }}
        style={{ width: "100%", height: "100%" }}
      >
        <Background color="var(--border)" gap={28} size={1} />
        <Controls showInteractive={false} position="bottom-left" />
        <MiniMap
          nodeColor={(n) => {
            const d = (n.data as NodeData) || {};
            switch (d.state) {
              case "running": return "var(--run)";
              case "done": return "var(--ok)";
              case "errored": return "var(--block)";
              case "queued": return "var(--queue)";
              default: return "var(--border-strong)";
            }
          }}
          maskColor="rgba(8,11,20,0.7)"
          style={{ background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 8 }}
          pannable
          zoomable
        />
      </ReactFlow>
      <div className="graph-overlay">
        <div className="graph-overlay-row">
          <span className={`tag ${sc.live ? "tag-live" : "tag-syn"}`}>{sc.live ? "LIVE" : "BLUEPRINT"}</span>
          <span className="graph-overlay-name">{sc.defName}</span>
          <span className="graph-overlay-sub">· {sc.version}</span>
          <span className="graph-overlay-dim">· {NODE_SIZE.width}×{NODE_SIZE.height} dagre LR</span>
        </div>
      </div>
    </div>
  );
}
