/* global React */
/* Draggable workflow graph — soft rounded nodes, flat-but-warm aesthetic.
   Replaces the old isometric cube cluster. Nodes can be dragged with
   mouse/touch; connections re-route live. Reset button returns to the
   default layout. */

function WorkflowGraph() {
  const { useState, useRef, useEffect, useCallback } = React;
  const t = window.t || function(de, en){ return de; };

  const VB_W = 520;
  const VB_H = 300;

  // Initial positions — wider, more breathing room than the iso grid
  const INITIAL = [
    { id: "cron",   x:  60, y:  40, l: "Cron",     k: "T" },
    { id: "wh",     x:  60, y:  95, l: "Webhook",  k: "T" },
    { id: "form",   x:  60, y: 150, l: "Form",     k: "T" },
    { id: "gmail",  x:  60, y: 205, l: "Gmail",    k: "T" },

    { id: "http1",  x: 155, y:  40, l: "HTTP",     k: "F" },
    { id: "auth",   x: 155, y:  95, l: "OAuth2",   k: "F" },
    { id: "parse",  x: 155, y: 150, l: "Parser",   k: "F" },
    { id: "valid",  x: 155, y: 205, l: "Valid.",   k: "F" },

    { id: "if1",    x: 250, y:  68, l: "IF",       k: "L" },
    { id: "switch", x: 250, y: 122, l: "Switch",   k: "L" },
    { id: "merge",  x: 250, y: 178, l: "Merge",    k: "L" },
    { id: "loop",   x: 250, y: 232, l: "Loop",     k: "L" },

    { id: "set1",   x: 345, y:  40, l: "Set",      k: "X" },
    { id: "code",   x: 345, y:  95, l: "Code",     k: "X" },
    { id: "ai",     x: 345, y: 150, l: "AI",       k: "A" },

    { id: "pg",     x: 450, y:  40, l: "Postgres", k: "O" },
    { id: "slack",  x: 450, y:  95, l: "Slack",    k: "O" },
    { id: "sheets", x: 450, y: 150, l: "Sheets",   k: "O" },
    { id: "wh2",    x: 450, y: 232, l: "Hook ⤴",  k: "O" },
  ];

  const EDGES = [
    ["cron", "http1"], ["wh", "auth"], ["form", "parse"], ["gmail", "valid"],
    ["http1", "if1"], ["auth", "if1"],
    ["parse", "switch"], ["valid", "switch"],
    ["valid", "merge"],
    ["if1", "set1"], ["if1", "code"],
    ["switch", "code"], ["switch", "ai"],
    ["merge", "loop"],
    ["set1", "pg"], ["code", "slack"],
    ["ai", "sheets"], ["ai", "slack"],
    ["loop", "wh2"], ["loop", "sheets"],
  ];

  const ANIMATED = [
    ["cron", "http1", 4],
    ["http1", "if1", 4.6],
    ["if1", "set1", 5.2],
    ["set1", "pg", 5.8],
    ["form", "parse", 4.2],
    ["parse", "switch", 5.0],
    ["switch", "ai", 5.4],
    ["ai", "sheets", 6.0],
  ];

  const KIND_COLOR = {
    T: "#c8a662", F: "#8b8478", L: "#a89668",
    X: "#c8a662", A: "#d4af6a", O: "#8b8478",
  };

  const NODE_W = 68;
  const NODE_H = 28;

  const [positions, setPositions] = useState(() =>
    Object.fromEntries(INITIAL.map((n) => [n.id, { x: n.x, y: n.y }]))
  );
  const [dragId, setDragId] = useState(null);
  const svgRef = useRef(null);
  const dragOffset = useRef({ dx: 0, dy: 0 });

  const N = Object.fromEntries(INITIAL.map((n) => [n.id, n]));
  const nodeAt = (id) => ({ ...N[id], ...positions[id] });

  const toSvgPoint = useCallback((clientX, clientY) => {
    const svg = svgRef.current;
    if (!svg) return { x: 0, y: 0 };
    const pt = svg.createSVGPoint();
    pt.x = clientX; pt.y = clientY;
    const ctm = svg.getScreenCTM();
    if (!ctm) return { x: 0, y: 0 };
    const local = pt.matrixTransform(ctm.inverse());
    return { x: local.x, y: local.y };
  }, []);

  const onPointerDown = (id) => (e) => {
    e.preventDefault();
    e.stopPropagation();
    e.currentTarget.setPointerCapture(e.pointerId);
    const p = toSvgPoint(e.clientX, e.clientY);
    const cur = positions[id];
    dragOffset.current = { dx: p.x - cur.x, dy: p.y - cur.y };
    setDragId(id);
  };

  const onPointerMove = (e) => {
    if (!dragId) return;
    const p = toSvgPoint(e.clientX, e.clientY);
    const nx = Math.max(NODE_W / 2 + 4, Math.min(VB_W - NODE_W / 2 - 4, p.x - dragOffset.current.dx));
    const ny = Math.max(NODE_H / 2 + 4, Math.min(VB_H - NODE_H / 2 - 4, p.y - dragOffset.current.dy));
    setPositions((prev) => ({ ...prev, [dragId]: { x: nx, y: ny } }));
  };

  const onPointerUp = () => setDragId(null);

  const reset = () =>
    setPositions(Object.fromEntries(INITIAL.map((n) => [n.id, { x: n.x, y: n.y }])));

  // Draw a smooth horizontal-bias bezier between two nodes
  const edgePath = (a, b) => {
    const A = nodeAt(a), B = nodeAt(b);
    const ax = A.x + NODE_W / 2;  // exit right
    const ay = A.y;
    const bx = B.x - NODE_W / 2;  // enter left
    const by = B.y;
    // If target is to the left, route around with vertical detour
    if (bx <= ax) {
      const midY = (ay + by) / 2;
      const off = Math.max(40, Math.abs(by - ay) * 0.5);
      return `M ${ax} ${ay} C ${ax + off} ${ay}, ${bx - off} ${by}, ${bx} ${by}`;
    }
    const dx = (bx - ax) * 0.5;
    return `M ${ax} ${ay} C ${ax + dx} ${ay}, ${bx - dx} ${by}, ${bx} ${by}`;
  };

  return (
    <div style={{ position: "relative" }}>
      <svg
        ref={svgRef}
        viewBox={`0 0 ${VB_W} ${VB_H}`}
        style={{ width: "100%", height: "auto", display: "block", touchAction: "none", cursor: dragId ? "grabbing" : "default" }}
        onPointerMove={onPointerMove}
        onPointerUp={onPointerUp}
        onPointerCancel={onPointerUp}
      >
        <defs>
          <linearGradient id="wf-node-fill" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="var(--bg-card)" />
            <stop offset="100%" stopColor="var(--bg-elev)" />
          </linearGradient>
          <linearGradient id="wf-node-fill-active" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="var(--bg-elev)" />
            <stop offset="100%" stopColor="var(--bg-card)" />
          </linearGradient>
          <pattern id="wf-grid" width="20" height="20" patternUnits="userSpaceOnUse">
            <circle cx="1" cy="1" r="0.6" fill="var(--line-strong)" opacity="0.5" />
          </pattern>
        </defs>

        {/* dotted background grid */}
        <rect x="0" y="0" width={VB_W} height={VB_H} fill="url(#wf-grid)" opacity="0.5" />

        {/* edges */}
        <g>
          {EDGES.map(([a, b], i) => (
            <path
              key={i}
              d={edgePath(a, b)}
              fill="none"
              stroke="var(--gold)"
              strokeWidth="1"
              opacity="0.45"
              strokeLinecap="round"
            />
          ))}
        </g>

        {/* animated data packets */}
        <g>
          {ANIMATED.map(([a, b, dur], i) => (
            <circle key={i} r="2.6" fill="var(--gold)">
              <animateMotion dur={`${dur}s`} repeatCount="indefinite" begin={`${i * 0.4}s`} path={edgePath(a, b)} />
            </circle>
          ))}
        </g>

        {/* nodes */}
        <g>
          {INITIAL.map((n) => {
            const p = positions[n.id];
            const col = KIND_COLOR[n.k] || "#8b8478";
            const isDragging = dragId === n.id;
            const x = p.x - NODE_W / 2;
            const y = p.y - NODE_H / 2;
            return (
              <g
                key={n.id}
                onPointerDown={onPointerDown(n.id)}
                style={{ cursor: isDragging ? "grabbing" : "grab" }}
              >
                {/* drop shadow */}
                <rect
                  x={x + 1.5}
                  y={y + 2.5}
                  width={NODE_W}
                  height={NODE_H}
                  rx={NODE_H / 2}
                  fill="#000"
                  opacity={isDragging ? 0.35 : 0.18}
                />
                {/* pill body */}
                <rect
                  x={x}
                  y={y}
                  width={NODE_W}
                  height={NODE_H}
                  rx={NODE_H / 2}
                  fill={isDragging ? "url(#wf-node-fill-active)" : "url(#wf-node-fill)"}
                  stroke={col}
                  strokeWidth={isDragging ? 1.4 : 0.8}
                />
                {/* type chip */}
                <circle cx={x + 11} cy={p.y} r="6.5" fill={col} />
                <text
                  x={x + 11}
                  y={p.y + 2.4}
                  textAnchor="middle"
                  fill="var(--bg)"
                  fontSize="7.5"
                  fontFamily="JetBrains Mono"
                  fontWeight="700"
                  style={{ pointerEvents: "none" }}
                >{n.k}</text>
                {/* label */}
                <text
                  x={x + 23}
                  y={p.y + 3.2}
                  fill="var(--ink)"
                  fontSize="9"
                  fontFamily="JetBrains Mono"
                  fontWeight="500"
                  style={{ pointerEvents: "none" }}
                >{n.l}</text>
                {/* in/out ports */}
                <circle cx={x} cy={p.y} r="1.8" fill={col} stroke="var(--bg)" strokeWidth="0.6" style={{ pointerEvents: "none" }} />
                <circle cx={x + NODE_W} cy={p.y} r="1.8" fill={col} stroke="var(--bg)" strokeWidth="0.6" style={{ pointerEvents: "none" }} />
              </g>
            );
          })}
        </g>

        {/* legend */}
        <g transform="translate(10 282)" fontFamily="JetBrains Mono" fontSize="7.5" letterSpacing="1">
          {[
            { k: "T", l: "Trigger" },
            { k: "F", l: "Fetch" },
            { k: "L", l: t("Logik", "Logic") },
            { k: "X", l: "Transform" },
            { k: "A", l: "AI" },
            { k: "O", l: "Output" },
          ].map((item, i) => (
            <g key={item.k} transform={`translate(${i * 76} 0)`}>
              <circle cx="5" cy="4" r="4.5" fill={KIND_COLOR[item.k]} />
              <text x="5" y="6.4" textAnchor="middle" fill="var(--bg)" fontSize="5.5" fontWeight="700">{item.k}</text>
              <text x="14" y="7" fill="var(--ink-mute)">{item.l}</text>
            </g>
          ))}
        </g>
      </svg>

      {/* drag hint + reset */}
      <div className="wf-controls">
        <span className="wf-hint">
          <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ marginRight: 4, verticalAlign: -2 }}>
            <path d="M5 9l-3 3 3 3" /><path d="M9 5l3-3 3 3" /><path d="M15 19l-3 3-3-3" /><path d="M19 9l3 3-3 3" /><path d="M2 12h20" /><path d="M12 2v20" />
          </svg>
          {t("Knoten zum Verschieben ziehen", "Drag nodes to move")}
        </span>
        <button className="wf-reset" onClick={reset}>{t("Zurücksetzen", "Reset")}</button>
      </div>
    </div>
  );
}

window.WorkflowGraph = WorkflowGraph;
