"use client";
import * as React from 'react';
import { clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
import { jsxs, jsx } 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 Chord({
  nodes,
  matrix,
  size = 480,
  padAngle = 0.04,
  onChordHover,
  onNodeClick,
  className,
  ...rest
}) {
  const [d3c, setD3c] = React.useState(null);
  const [d3s, setD3s] = React.useState(null);
  const [importError, setImportError] = React.useState(false);
  React.useEffect(() => {
    let cancelled = false;
    void Promise.all([import('d3-chord'), import('d3-shape')]).then(
      ([c, s]) => {
        if (cancelled) return;
        setD3c(c);
        setD3s(s);
      },
      () => {
        if (!cancelled) setImportError(true);
      }
    );
    return () => {
      cancelled = true;
    };
  }, []);
  const laidOut = React.useMemo(() => {
    if (!d3c || !d3s) return null;
    return layout(d3c, d3s, nodes, matrix, size, padAngle);
  }, [d3c, d3s, nodes, matrix, size, padAngle]);
  if (importError) {
    return /* @__PURE__ */ jsxs(
      "div",
      {
        "data-hex-chord-error": true,
        role: "alert",
        className: cn(
          "inline-flex items-center justify-center rounded-md border border-destructive/40 bg-destructive/5 p-3 text-sm text-destructive",
          className
        ),
        style: { width: size, height: size },
        children: [
          "Install ",
          /* @__PURE__ */ jsx("code", { className: "mx-1", children: "d3-chord" }),
          " to view this chord diagram."
        ]
      }
    );
  }
  if (!laidOut) {
    return /* @__PURE__ */ jsx(
      "div",
      {
        "data-hex-chord-loading": true,
        "aria-busy": "true",
        "aria-label": "Loading chord diagram",
        className: cn("inline-block bg-muted/20", className),
        style: { width: size, height: size }
      }
    );
  }
  const { arcs, chords } = laidOut;
  const desc = `Chord diagram with ${nodes.length} node${nodes.length === 1 ? "" : "s"} and ${chords.length} ribbon${chords.length === 1 ? "" : "s"}`;
  const radius = size / 2;
  return /* @__PURE__ */ jsxs(
    "svg",
    {
      ...rest,
      "data-hex-chord": true,
      role: "img",
      width: size,
      height: size,
      viewBox: `${-radius} ${-radius} ${size} ${size}`,
      className: cn("block", className),
      children: [
        /* @__PURE__ */ jsx("title", { children: "Chord diagram" }),
        /* @__PURE__ */ jsx("desc", { children: desc }),
        /* @__PURE__ */ jsx("g", { "data-hex-chord-ribbons": true, children: chords.map((c, i) => {
          const interactive = Boolean(onChordHover);
          const payload = {
            source: c.source,
            target: c.target,
            sourceValue: c.sourceValue,
            targetValue: c.targetValue
          };
          const fireHover = (chord) => onChordHover?.(chord);
          return /* @__PURE__ */ jsx(
            "path",
            {
              "data-hex-chord-ribbon": true,
              d: c.d,
              className: interactive ? "focus-visible:outline-none focus-visible:outline-2 focus-visible:outline-ring" : void 0,
              fill: pickChartHue(c.sourceIdx),
              fillOpacity: 0.55,
              stroke: "hsl(var(--background))",
              strokeWidth: 0.5,
              role: interactive ? "button" : void 0,
              tabIndex: interactive ? 0 : void 0,
              "aria-label": interactive ? `Flow from ${c.source.label} to ${c.target.label}, value ${c.sourceValue}; reverse value ${c.targetValue}` : void 0,
              style: {
                cursor: interactive ? "pointer" : void 0,
                transition: "fill-opacity 120ms ease"
              },
              onMouseEnter: interactive ? () => fireHover(payload) : void 0,
              onMouseLeave: interactive ? () => fireHover(null) : void 0,
              onFocus: interactive ? () => fireHover(payload) : void 0,
              onBlur: interactive ? () => fireHover(null) : void 0
            },
            `${c.source.id}-${c.target.id}-${i}`
          );
        }) }),
        /* @__PURE__ */ jsx("g", { "data-hex-chord-arcs": true, children: arcs.map((a) => {
          const interactive = Boolean(onNodeClick);
          const handleActivate = () => onNodeClick?.(a.node);
          const flip = a.labelAngle > Math.PI / 2 && a.labelAngle < 3 * Math.PI / 2;
          return /* @__PURE__ */ jsxs(
            "g",
            {
              "data-hex-chord-arc": true,
              "data-depth": a.depth,
              className: interactive ? "focus-visible:outline-none focus-visible:outline-2 focus-visible:outline-ring" : void 0,
              role: interactive ? "button" : void 0,
              tabIndex: interactive ? 0 : void 0,
              "aria-label": interactive ? a.node.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(
                  "path",
                  {
                    d: a.d,
                    fill: pickChartHue(a.depth),
                    stroke: "hsl(var(--background))",
                    strokeWidth: 1
                  }
                ),
                /* @__PURE__ */ jsx(
                  "text",
                  {
                    x: a.labelX,
                    y: a.labelY,
                    textAnchor: flip ? "end" : "start",
                    dy: "0.35em",
                    transform: flip ? `rotate(${a.labelAngle * 180 / Math.PI - 270} ${a.labelX} ${a.labelY})` : `rotate(${a.labelAngle * 180 / Math.PI - 90} ${a.labelX} ${a.labelY})`,
                    fontSize: 11,
                    fill: "hsl(var(--foreground))",
                    style: { pointerEvents: "none" },
                    children: a.node.label
                  }
                )
              ]
            },
            a.node.id
          );
        }) })
      ]
    }
  );
}
function layout(d3c, d3s, nodes, matrix, size, padAngle) {
  const longestLabel = nodes.reduce((m, n) => Math.max(m, n.label.length), 0);
  const labelMargin = Math.max(40, longestLabel * 6 + 16);
  const radius = size / 2 - labelMargin;
  const innerRadius = radius - 12;
  const outerRadius = radius;
  const chordGen = d3c.chord().padAngle(padAngle).sortSubgroups((a, b) => a < b ? 1 : a > b ? -1 : 0);
  const result = chordGen(matrix);
  const arc = d3s.arc().innerRadius(innerRadius).outerRadius(outerRadius);
  const ribbon = d3c.ribbon().radius(innerRadius);
  const arcs = result.groups.map((g) => {
    const node = nodes[g.index] ?? { id: `_${g.index}`, label: `Set ${g.index}` };
    const midAngle = (g.startAngle + g.endAngle) / 2;
    const labelRadius = outerRadius + 6;
    return {
      node,
      depth: g.index,
      d: arc({ startAngle: g.startAngle, endAngle: g.endAngle, innerRadius, outerRadius }) ?? "",
      labelX: labelRadius * Math.sin(midAngle),
      labelY: -labelRadius * Math.cos(midAngle),
      labelAngle: midAngle
    };
  });
  const buildRibbonInput = (c) => ({
    source: { ...c.source, radius: innerRadius },
    target: { ...c.target, radius: innerRadius }
  });
  const chords = result.filter((c) => c.source.value > 0 || c.target.value > 0).map((c) => ({
    source: nodes[c.source.index] ?? { id: `_${c.source.index}`, label: `Set ${c.source.index}` },
    target: nodes[c.target.index] ?? { id: `_${c.target.index}`, label: `Set ${c.target.index}` },
    sourceValue: c.source.value,
    targetValue: c.target.value,
    d: ribbon(buildRibbonInput(c)) ?? "",
    sourceIdx: c.source.index
  }));
  return { arcs, chords };
}
function activateOnKey(e, fn) {
  if (e.key === "Enter" || e.key === " ") {
    e.preventDefault();
    fn();
  }
}

export { Chord };
//# sourceMappingURL=chord.js.map
//# sourceMappingURL=chord.js.map