"use client";
import * as React from 'react';
import { clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
import { jsx, jsxs } from 'react/jsx-runtime';

// src/lib/chart-palette.ts
var CHART_PALETTE = [
  "hsl(var(--chart-1, var(--primary)))",
  "hsl(var(--chart-2, var(--primary)))",
  "hsl(var(--chart-3, var(--primary)))",
  "hsl(var(--chart-4, var(--primary)))",
  "hsl(var(--chart-5, var(--primary)))",
  "hsl(var(--chart-6, var(--primary)))"
];
function pickChartHue(index) {
  const safe = (index % CHART_PALETTE.length + CHART_PALETTE.length) % CHART_PALETTE.length;
  return CHART_PALETTE[safe];
}
function cn(...inputs) {
  return twMerge(clsx(inputs));
}
function Sankey({
  nodes,
  links,
  width = 720,
  height = 420,
  nodeAlign = "justify",
  nodeWidth = 12,
  nodePadding = 8,
  onLinkHover,
  onNodeClick,
  className,
  ...rest
}) {
  const [d3s, setD3s] = React.useState(null);
  React.useEffect(() => {
    let cancelled = false;
    void import('d3-sankey').then((mod) => {
      if (!cancelled) setD3s(mod);
    });
    return () => {
      cancelled = true;
    };
  }, []);
  const laidOut = React.useMemo(() => {
    if (!d3s) return null;
    return layout(d3s, nodes, links, width, height, nodeAlign, nodeWidth, nodePadding);
  }, [d3s, nodes, links, width, height, nodeAlign, nodeWidth, nodePadding]);
  if (!d3s || !laidOut) {
    return /* @__PURE__ */ jsx(
      "div",
      {
        "data-hex-sankey-loading": true,
        "aria-busy": "true",
        "aria-label": "Loading Sankey diagram",
        className: cn("inline-block bg-muted/20", className),
        style: { width, height }
      }
    );
  }
  const { nodes: laidOutNodes, links: laidOutLinks } = laidOut;
  const desc = `Sankey diagram with ${nodes.length} node${nodes.length === 1 ? "" : "s"} and ${links.length} link${links.length === 1 ? "" : "s"}`;
  return /* @__PURE__ */ jsxs(
    "svg",
    {
      ...rest,
      "data-hex-sankey": true,
      "data-node-align": nodeAlign,
      role: "img",
      width,
      height,
      viewBox: `0 0 ${width} ${height}`,
      className: cn("block", className),
      children: [
        /* @__PURE__ */ jsx("title", { children: "Sankey diagram" }),
        /* @__PURE__ */ jsx("desc", { children: desc }),
        /* @__PURE__ */ jsx("g", { "data-hex-sankey-links": true, fill: "none", children: laidOutLinks.map((l, i) => {
          const interactive = Boolean(onLinkHover);
          const fireHover = (link) => onLinkHover?.(link);
          const stroke = pickChartHue(l.sourceIdx);
          return /* @__PURE__ */ jsx(
            "path",
            {
              "data-hex-sankey-link": true,
              d: l.d,
              stroke,
              strokeOpacity: 0.45,
              strokeWidth: Math.max(1, l.width),
              role: interactive ? "button" : void 0,
              tabIndex: interactive ? 0 : void 0,
              "aria-label": interactive ? `Flow: ${l.original.source} \u2192 ${l.original.target} (${l.original.value})` : void 0,
              style: {
                cursor: interactive ? "pointer" : void 0,
                transition: "stroke-opacity 120ms ease"
              },
              onMouseEnter: interactive ? () => fireHover(l.original) : void 0,
              onMouseLeave: interactive ? () => fireHover(null) : void 0,
              onFocus: interactive ? () => fireHover(l.original) : void 0,
              onBlur: interactive ? () => fireHover(null) : void 0
            },
            `${l.original.source}-${l.original.target}-${i}`
          );
        }) }),
        /* @__PURE__ */ jsx("g", { "data-hex-sankey-nodes": true, children: laidOutNodes.map((n) => {
          const w = n.x1 - n.x0;
          const h = n.y1 - n.y0;
          const isRightSide = n.x0 > width / 2;
          const interactive = Boolean(onNodeClick);
          const handleActivate = () => onNodeClick?.(n.original);
          const fill = pickChartHue(n.idx);
          return /* @__PURE__ */ jsxs(
            "g",
            {
              "data-hex-sankey-node": true,
              className: interactive ? "focus-visible:outline-none focus-visible:outline-2 focus-visible:outline-ring" : void 0,
              transform: `translate(${n.x0},${n.y0})`,
              role: interactive ? "button" : void 0,
              tabIndex: interactive ? 0 : void 0,
              "aria-label": interactive ? n.original.label : void 0,
              style: interactive ? { cursor: "pointer" } : void 0,
              onClick: interactive ? handleActivate : void 0,
              onKeyDown: interactive ? (e) => activateOnKey(e, handleActivate) : void 0,
              children: [
                /* @__PURE__ */ jsx("rect", { width: w, height: h, fill, stroke: "hsl(var(--background))" }),
                /* @__PURE__ */ jsx(
                  "text",
                  {
                    x: isRightSide ? -6 : w + 6,
                    y: h / 2,
                    dy: "0.35em",
                    fontSize: 12,
                    fontWeight: 500,
                    fill: "hsl(var(--foreground))",
                    textAnchor: isRightSide ? "end" : "start",
                    style: { pointerEvents: "none" },
                    children: n.original.label
                  }
                )
              ]
            },
            n.original.id
          );
        }) })
      ]
    }
  );
}
function layout(d3s, nodes, links, width, height, align, nodeWidth, nodePadding) {
  const alignFn = align === "left" ? d3s.sankeyLeft : align === "right" ? d3s.sankeyRight : align === "center" ? d3s.sankeyCenter : d3s.sankeyJustify;
  const nodesClone = nodes.map((n) => ({ ...n }));
  const linksClone = links.map((l) => ({ ...l }));
  const sankeyGen = d3s.sankey().nodeId((d) => d.id).nodeAlign(alignFn).nodeWidth(nodeWidth).nodePadding(nodePadding).extent([
    [1, 1],
    [width - 1, height - 1]
  ]);
  const result = sankeyGen({ nodes: nodesClone, links: linksClone });
  const linkPath = d3s.sankeyLinkHorizontal();
  const idByIndex = /* @__PURE__ */ new Map();
  nodes.forEach((n, i) => idByIndex.set(n.id, i));
  return {
    nodes: result.nodes.map((n, i) => ({
      original: { ...nodes[i] },
      x0: n.x0 ?? 0,
      x1: n.x1 ?? 0,
      y0: n.y0 ?? 0,
      y1: n.y1 ?? 0,
      idx: i
    })),
    links: result.links.map((l, i) => {
      const sourceId = typeof l.source === "string" ? l.source : l.source.id;
      const targetId = typeof l.target === "string" ? l.target : l.target.id;
      return {
        original: { ...links[i], source: sourceId, target: targetId, value: l.value },
        d: linkPath(l) ?? "",
        width: l.width ?? 1,
        sourceIdx: idByIndex.get(sourceId) ?? 0
      };
    })
  };
}
function activateOnKey(e, fn) {
  if (e.key === "Enter" || e.key === " ") {
    e.preventDefault();
    fn();
  }
}

export { Sankey };
//# sourceMappingURL=sankey.js.map
//# sourceMappingURL=sankey.js.map