"use client";

/**
 * KnowledgeGraphView - 纯 SVG 知识图谱可视化组件
 *
 * 职责：
 * - 圆形布局放置知识点节点
 * - 节点大小 = 掌握度，颜色 = 掌握度梯度（红→黄→绿，使用语义令牌）
 * - 边为箭头线（PREREQUISITE 实线 / RELATED 虚线）
 * - 点击节点展示详情面板
 *
 * 不依赖 d3/recharts，全部 SVG 手绘（project_rules：不安装新 npm 包）。
 * 颜色禁止 hex 字面量，使用 var(--color-success/warning/danger)（project_rules §3.10）。
 *
 * 维护者：ai13（teacher-portal）
 */

import { useMemo, useState } from "react";
import type {
  KnowledgeNode,
  KnowledgeEdge,
} from "@/lib/graphql-p4";

interface KnowledgeGraphViewProps {
  nodes: KnowledgeNode[];
  edges: KnowledgeEdge[];
}

/** 画布尺寸 */
const WIDTH = 880;
const HEIGHT = 620;
const CENTER_X = WIDTH / 2;
const CENTER_Y = HEIGHT / 2;
/** 节点分布圆半径 */
const LAYOUT_RADIUS = 230;
/** 节点最小/最大半径 */
const NODE_R_MIN = 18;
const NODE_R_MAX = 34;

/** 按掌握度映射填充色（语义令牌变量） */
function masteryColor(level: number): string {
  if (level < 40) return "var(--color-danger)";
  if (level < 70) return "var(--color-warning)";
  return "var(--color-success)";
}

/** 按掌握度映射节点半径 */
function nodeRadius(level: number): number {
  const ratio = Math.max(0, Math.min(100, level)) / 100;
  return NODE_R_MIN + (NODE_R_MAX - NODE_R_MIN) * ratio;
}

interface NodePosition {
  node: KnowledgeNode;
  x: number;
  y: number;
  r: number;
}

export default function KnowledgeGraphView({
  nodes,
  edges,
}: KnowledgeGraphViewProps): React.ReactNode {
  const [selectedId, setSelectedId] = useState<string | null>(
    nodes[0]?.id ?? null,
  );

  // 圆形布局：按 index 均匀分布
  const positions = useMemo<NodePosition[]>(() => {
    const total = nodes.length;
    return nodes.map((node, i) => {
      const angle = (2 * Math.PI * i) / total - Math.PI / 2;
      return {
        node,
        x: CENTER_X + LAYOUT_RADIUS * Math.cos(angle),
        y: CENTER_Y + LAYOUT_RADIUS * Math.sin(angle),
        r: nodeRadius(node.masteryLevel),
      };
    });
  }, [nodes]);

  const posMap = useMemo(() => {
    const m = new Map<string, NodePosition>();
    positions.forEach((p) => m.set(p.node.id, p));
    return m;
  }, [positions]);

  const selected = selectedId
    ? positions.find((p) => p.node.id === selectedId) ?? null
    : null;

  return (
    <div className="flex gap-8 items-start">
      {/* SVG 图谱 */}
      <svg
        viewBox={`0 0 ${WIDTH} ${HEIGHT}`}
        className="flex-1 max-w-3xl border border-rule rounded-card bg-surface"
        role="img"
        aria-label="知识图谱节点关系图"
      >
        <defs>
          {/* 箭头标记 - PREREQUISITE */}
          <marker
            id="arrow-prereq"
            viewBox="0 0 10 10"
            refX="9"
            refY="5"
            markerWidth="7"
            markerHeight="7"
            orient="auto-start-reverse"
          >
            <path
              d="M 0 0 L 10 5 L 0 10 z"
              fill="var(--color-ink-muted)"
            />
          </marker>
          {/* 箭头标记 - RELATED */}
          <marker
            id="arrow-related"
            viewBox="0 0 10 10"
            refX="9"
            refY="5"
            markerWidth="7"
            markerHeight="7"
            orient="auto-start-reverse"
          >
            <path
              d="M 0 0 L 10 5 L 0 10 z"
              fill="var(--color-ink-subtle)"
            />
          </marker>
        </defs>

        {/* 边 */}
        <g>
          {edges.map((edge, i) => {
            const from = posMap.get(edge.from);
            const to = posMap.get(edge.to);
            if (!from || !to) return null;

            // 计算边起止点（缩进到节点边缘，避免穿过节点）
            const dx = to.x - from.x;
            const dy = to.y - from.y;
            const dist = Math.sqrt(dx * dx + dy * dy) || 1;
            const ux = dx / dist;
            const uy = dy / dist;
            const x1 = from.x + ux * from.r;
            const y1 = from.y + uy * from.r;
            const x2 = to.x - ux * (to.r + 4);
            const y2 = to.y - uy * (to.r + 4);

            const isPrereq = edge.type === "PREREQUISITE";
            return (
              <line
                key={`edge-${i}`}
                x1={x1}
                y1={y1}
                x2={x2}
                y2={y2}
                stroke={isPrereq ? "var(--color-ink-muted)" : "var(--color-ink-subtle)"}
                strokeWidth={isPrereq ? 1.5 : 1}
                strokeDasharray={isPrereq ? undefined : "5 4"}
                markerEnd={isPrereq ? "url(#arrow-prereq)" : "url(#arrow-related)"}
              />
            );
          })}
        </g>

        {/* 节点 */}
        <g>
          {positions.map((p) => {
            const isSelected = p.node.id === selectedId;
            return (
              <g
                key={p.node.id}
                onClick={() => setSelectedId(p.node.id)}
                className="cursor-pointer"
                role="button"
                aria-label={`${p.node.name} 掌握度 ${p.node.masteryLevel}`}
              >
                <circle
                  cx={p.x}
                  cy={p.y}
                  r={p.r}
                  fill={masteryColor(p.node.masteryLevel)}
                  fillOpacity={0.85}
                  stroke={
                    isSelected
                      ? "var(--color-ink)"
                      : "var(--color-rule)"
                  }
                  strokeWidth={isSelected ? 2.5 : 1}
                />
                <text
                  x={p.x}
                  y={p.y + p.r + 16}
                  textAnchor="middle"
                  fontSize="13"
                  fontFamily="var(--font-family-sans)"
                  fill="var(--color-ink)"
                >
                  {p.node.name}
                </text>
                <text
                  x={p.x}
                  y={p.y + 5}
                  textAnchor="middle"
                  fontSize="12"
                  fontFamily="var(--font-family-mono)"
                  fontWeight="600"
                  fill="var(--color-ink-on-accent)"
                >
                  {p.node.masteryLevel}
                </text>
              </g>
            );
          })}
        </g>
      </svg>

      {/* 详情面板 */}
      <aside className="w-72 flex-shrink-0">
        {selected ? (
          <div className="p-6 border border-rule rounded-card bg-surface">
            <p className="text-tiny uppercase tracking-wide text-ink-muted">
              {selected.node.subject}
            </p>
            <h3 className="mt-2 text-xl font-serif text-ink">
              {selected.node.name}
            </h3>
            {selected.node.description ? (
              <p className="mt-3 text-sm text-ink-muted">
                {selected.node.description}
              </p>
            ) : null}

            <div className="rule-thin my-5" />

            <div>
              <div className="flex items-baseline justify-between mb-2">
                <span className="text-tiny uppercase tracking-wide text-ink-muted">
                  掌握度
                </span>
                <span
                  className="text-lg font-serif"
                  style={{ color: masteryColor(selected.node.masteryLevel) }}
                >
                  {selected.node.masteryLevel}
                  <span className="text-tiny text-ink-muted">/100</span>
                </span>
              </div>
              <div className="h-2 rounded-button bg-subtle overflow-hidden">
                <div
                  className="h-full rounded-button"
                  style={{
                    width: `${selected.node.masteryLevel}%`,
                    background: masteryColor(selected.node.masteryLevel),
                  }}
                />
              </div>
            </div>

            {/* 前置 / 后继 */}
            <Predecessors
              edges={edges}
              nodeId={selected.node.id}
              posMap={posMap}
            />
            <Successors
              edges={edges}
              nodeId={selected.node.id}
              posMap={posMap}
            />
          </div>
        ) : (
          <p className="text-sm text-ink-muted p-6">
            点击节点查看详情
          </p>
        )}

        {/* 图例 */}
        <div className="mt-6 p-4 border border-rule rounded-card">
          <p className="text-tiny uppercase tracking-wide text-ink-muted mb-3">
            图例
          </p>
          <ul className="space-y-2 text-sm">
            <li className="flex items-center gap-3">
              <span
                className="inline-block w-4 h-4 rounded-full"
                style={{ background: "var(--color-success)" }}
              />
              <span className="text-ink">掌握度 ≥ 70</span>
            </li>
            <li className="flex items-center gap-3">
              <span
                className="inline-block w-4 h-4 rounded-full"
                style={{ background: "var(--color-warning)" }}
              />
              <span className="text-ink">40 ≤ 掌握度 &lt; 70</span>
            </li>
            <li className="flex items-center gap-3">
              <span
                className="inline-block w-4 h-4 rounded-full"
                style={{ background: "var(--color-danger)" }}
              />
              <span className="text-ink">掌握度 &lt; 40</span>
            </li>
            <li className="flex items-center gap-3 pt-2 border-t border-rule">
              <span className="inline-block w-6 h-0.5 bg-ink-muted" />
              <span className="text-ink-muted">前置依赖（实线）</span>
            </li>
            <li className="flex items-center gap-3">
              <span
                className="inline-block w-6 h-0.5"
                style={{
                  backgroundImage:
                    "repeating-linear-gradient(90deg, var(--color-ink-subtle) 0 5px, transparent 5px 9px)",
                }}
              />
              <span className="text-ink-muted">关联（虚线）</span>
            </li>
          </ul>
        </div>
      </aside>
    </div>
  );
}

/** 前置节点列表 */
function Predecessors({
  edges,
  nodeId,
  posMap,
}: {
  edges: KnowledgeEdge[];
  nodeId: string;
  posMap: Map<string, NodePosition>;
}): React.ReactNode {
  const preds = edges
    .filter((e) => e.to === nodeId)
    .map((e) => posMap.get(e.from)?.node)
    .filter((n): n is KnowledgeNode => n !== undefined);

  if (preds.length === 0) return null;

  return (
    <div className="mt-5">
      <p className="text-tiny uppercase tracking-wide text-ink-muted mb-2">
        前置知识点
      </p>
      <ul className="space-y-1">
        {preds.map((n) => (
          <li key={n.id} className="text-sm text-ink">
            {n.name}
            <span className="ml-2 text-tiny text-ink-muted">
              {n.subject}
            </span>
          </li>
        ))}
      </ul>
    </div>
  );
}

/** 后继节点列表 */
function Successors({
  edges,
  nodeId,
  posMap,
}: {
  edges: KnowledgeEdge[];
  nodeId: string;
  posMap: Map<string, NodePosition>;
}): React.ReactNode {
  const succs = edges
    .filter((e) => e.from === nodeId)
    .map((e) => posMap.get(e.to)?.node)
    .filter((n): n is KnowledgeNode => n !== undefined);

  if (succs.length === 0) return null;

  return (
    <div className="mt-5">
      <p className="text-tiny uppercase tracking-wide text-ink-muted mb-2">
        后继知识点
      </p>
      <ul className="space-y-1">
        {succs.map((n) => (
          <li key={n.id} className="text-sm text-ink">
            {n.name}
            <span className="ml-2 text-tiny text-ink-muted">
              {n.subject}
            </span>
          </li>
        ))}
      </ul>
    </div>
  );
}
