import type { GraphNode } from "@/lib/lexicon";

const REL_COLOR: Record<string, string> = {
  hypernym: "#576139",
  hyponym: "#486830",
  mero_part: "#886620",
  mero_substance: "#a0733a",
  mero_member: "#b8864c",
  holo_part: "#7a667a",
  holo_substance: "#918091",
  holo_member: "#a89aa8",
  attribute: "#a85070",
};

/**
 * Mini force-directed-style semantic graph (SRS §7.7.2, §8.1.2, §9.2).
 * Renders the focus synset at the centre with immediate neighbours laid
 * out radially. Nodes are clickable for graph navigation. When
 * `showIds` is false (Visitor view) no synset IDs are rendered — nodes
 * are labelled by their Bengali words only.
 */
export function SemanticGraph({
  nodes,
  showIds,
  hrefFor,
  width = 640,
  height = 420,
}: {
  nodes: GraphNode[];
  showIds: boolean;
  /** Build the navigation URL for a node; return null for non-clickable. */
  hrefFor: (node: GraphNode) => string | null;
  width?: number;
  height?: number;
}) {
  if (nodes.length === 0) return null;
  const centre = nodes[0];
  const neighbours = nodes.slice(1);
  const cx = width / 2;
  const cy = height / 2;
  const radius = Math.min(width, height) / 2 - 70;

  const placed = neighbours.map((node, i) => {
    // Distribute outgoing relations on top half, incoming on bottom
    const angle =
      (2 * Math.PI * i) / neighbours.length - Math.PI / 2 +
      (neighbours.length === 1 ? Math.PI / 4 : 0);
    const jitter = i % 2 === 0 ? 0 : 18;
    return {
      node,
      x: cx + (radius + jitter) * Math.cos(angle),
      y: cy + (radius + jitter) * Math.sin(angle),
    };
  });

  const label = (n: GraphNode, max = 16) => {
    const word = n.words[0] ?? (showIds ? n.synsetId : "—");
    return word.length > max ? `${word.slice(0, max)}…` : word;
  };

  const usedRels = [...new Set(neighbours.map((n) => n.relation))];

  return (
    <figure>
      <svg
        viewBox={`0 0 ${width} ${height}`}
        className="h-auto w-full select-none"
        role="img"
        aria-label="Semantic neighbourhood graph"
      >
        {/* edges */}
        {placed.map(({ node, x, y }) => (
          <g key={`edge-${node.synsetId}-${node.relation}`}>
            <line
              x1={cx}
              y1={cy}
              x2={x}
              y2={y}
              stroke={REL_COLOR[node.relation] ?? "#c0be9e"}
              strokeWidth={1.5}
              strokeDasharray={node.direction === "in" ? "4 3" : undefined}
              opacity={0.55}
            />
            <text
              x={(cx + x) / 2}
              y={(cy + y) / 2 - 4}
              textAnchor="middle"
              fontSize={9}
              fill={REL_COLOR[node.relation] ?? "#848870"}
              className="font-medium"
            >
              {node.relation}
            </text>
          </g>
        ))}

        {/* neighbour nodes */}
        {placed.map(({ node, x, y }) => {
          const href = hrefFor(node);
          const circle = (
            <g
              className={href ? "cursor-pointer" : undefined}
              key={`node-${node.synsetId}-${node.relation}`}
            >
              <circle
                cx={x}
                cy={y}
                r={26}
                fill="white"
                stroke={REL_COLOR[node.relation] ?? "#c0be9e"}
                strokeWidth={2}
              />
              <text
                x={x}
                y={y + 1}
                textAnchor="middle"
                fontSize={11}
                className="font-bengali fill-slate-800 font-semibold"
              >
                {label(node, 8)}
              </text>
              {showIds ? (
                <text
                  x={x}
                  y={y + 40}
                  textAnchor="middle"
                  fontSize={8}
                  className="fill-slate-400 font-mono"
                >
                  {node.synsetId}
                </text>
              ) : null}
            </g>
          );
          return href ? (
            <a href={href} key={`link-${node.synsetId}-${node.relation}`}>
              {circle}
            </a>
          ) : (
            circle
          );
        })}

        {/* centre node */}
        <g>
          <circle
            cx={cx}
            cy={cy}
            r={36}
            fill="#576139"
            stroke="#3e4828"
            strokeWidth={2}
          />
          <text
            x={cx}
            y={cy + 2}
            textAnchor="middle"
            fontSize={13}
            className="font-bengali fill-white font-bold"
          >
            {label(centre, 10)}
          </text>
          {showIds ? (
            <text
              x={cx}
              y={cy + 52}
              textAnchor="middle"
              fontSize={9}
              className="fill-slate-500 font-mono"
            >
              {centre.synsetId}
            </text>
          ) : null}
        </g>
      </svg>
      <figcaption className="mt-2 flex flex-wrap items-center gap-x-4 gap-y-1 text-[11px] text-slate-500">
        {usedRels.map((rel) => (
          <span key={rel} className="inline-flex items-center gap-1.5">
            <span
              className="inline-block h-2 w-2 rounded-full"
              style={{ background: REL_COLOR[rel] ?? "#c0be9e" }}
            />
            {rel}
          </span>
        ))}
        <span className="ml-auto italic">
          dashed = incoming relation · click a node to navigate
        </span>
      </figcaption>
    </figure>
  );
}
