/**
 * 关系图谱 — Canvas 绘制逻辑
 *
 * 纯函数模块，不依赖 React。所有绘制函数接收 CanvasRenderingContext2D，
 * 不持有状态，可安全在 requestAnimationFrame 循环中调用。
 */

import type { GraphEdge } from './graphTypes';

// ── 常量 ──

/** 关系类型对应的色板 (base / light / glow) — 通用调色板自动分配 */
const EDGE_PALETTE: Array<{ base: string; light: string; glow: string }> = [
  { base: '#2563eb', light: '#60a5fa', glow: 'rgba(79,70,229,0.3)' },
  { base: '#059669', light: '#34D399', glow: 'rgba(5,150,105,0.3)' },
  { base: '#d97706', light: '#FBBF24', glow: 'rgba(217,119,6,0.3)' },
  { base: '#0891B2', light: '#22D3EE', glow: 'rgba(8,145,178,0.3)' },
  { base: '#dc2626', light: '#F87171', glow: 'rgba(220,38,38,0.3)' },
  { base: '#7C3AED', light: '#A78BFA', glow: 'rgba(124,58,237,0.3)' },
  { base: '#EA580C', light: '#FB923C', glow: 'rgba(234,88,12,0.3)' },
  { base: '#DB2777', light: '#F472B6', glow: 'rgba(219,39,119,0.3)' },
];

/** 未匹配到已知关系类型时的默认色 */
export const DEFAULT_REL_COLOR = { base: '#7C3AED', light: '#A78BFA', glow: 'rgba(124,58,237,0.3)' };

const edgeColorCache = new Map<string, { base: string; light: string; glow: string }>();

export function getEdgeColorGlobal(label: string) {
  const cached = edgeColorCache.get(label);
  if (cached) return cached;
  const color = EDGE_PALETTE[edgeColorCache.size % EDGE_PALETTE.length];
  edgeColorCache.set(label, color);
  return color;
}

/** @deprecated 使用 getEdgeColorGlobal */
export const RELATIONSHIP_COLORS = new Proxy({} as Record<string, { base: string; light: string; glow: string }>, {
  get(_, prop: string) { return getEdgeColorGlobal(prop); },
});

/** @deprecated 标签直接使用原始值 */
export const REL_LABEL_MAP = new Proxy({} as Record<string, string>, {
  get(_, prop: string) { return prop; },
});

/** 通用边颜色函数 — 兼容旧路径导入 */
export function getEdgeColor(label: string) {
  return getEdgeColorGlobal(label);
}

/** 普通节点基础半径 */
export const NODE_BASE_RADIUS = 18;
/** 中心节点半径 */
export const NODE_CENTER_RADIUS = 26;
/** 悬停放大系数 */
export const NODE_HOVER_SCALE = 1.3;
/** 节点标签最大字符数 */
export const LABEL_MAX_LENGTH = 8;

// ── Helper ──

/** 根据 label 获取关系色板，未匹配时返回默认。 */
export function getRelColor(label: string) {
  return RELATIONSHIP_COLORS[label] || DEFAULT_REL_COLOR;
}

/** 将关系类型 key 转为中文标签。 */
export function getEdgeTypeLabel(label: string): string {
  return REL_LABEL_MAP[label] || label;
}

/** 截断过长标签。 */
export function truncateLabel(label: string): string {
  return label.length > LABEL_MAX_LENGTH
    ? label.slice(0, LABEL_MAX_LENGTH) + '...'
    : label;
}

/** 计算节点的度 (degree)，即与之相连的边数。 */
export function getNodeDegree(nodeId: string, edges: GraphEdge[]): number {
  return edges.filter((e) => e.source === nodeId || e.target === nodeId).length;
}

/** 将 degree 映射为节点半径，连接越多节点越大。 */
export function degreeToRadius(degree: number, isCenter: boolean): number {
  const base = isCenter ? NODE_CENTER_RADIUS : NODE_BASE_RADIUS;
  const bonus = Math.min(degree * 1.2, 10);
  return base + bonus;
}

// ── 绘制函数 ──

/** 绘制二次贝塞尔曲线边并带箭头，返回标签放置坐标。 */
export function drawCurvedEdge(
  ctx: CanvasRenderingContext2D,
  fromX: number,
  fromY: number,
  toX: number,
  toY: number,
  color: string,
  lineWidth: number,
  highlighted: boolean,
  alpha: number,
): { labelX: number; labelY: number } | undefined {
  const dx = toX - fromX;
  const dy = toY - fromY;
  const dist = Math.sqrt(dx * dx + dy * dy);
  if (dist < 1) return undefined;

  // 控制点：边中点的垂直方向偏移
  const curvature = Math.min(dist * 0.15, 30);
  const midX = (fromX + toX) / 2;
  const midY = (fromY + toY) / 2;
  const nx = -dy / dist;
  const ny = dx / dist;
  const cpX = midX + nx * curvature;
  const cpY = midY + ny * curvature;

  ctx.save();
  ctx.globalAlpha = alpha;
  ctx.strokeStyle = color;
  ctx.lineWidth = highlighted ? lineWidth + 1 : lineWidth;

  if (highlighted) {
    ctx.shadowColor = color;
    ctx.shadowBlur = 8;
  }

  ctx.beginPath();
  ctx.moveTo(fromX, fromY);
  ctx.quadraticCurveTo(cpX, cpY, toX, toY);
  ctx.stroke();

  // 箭头
  const arrowT = 0.95;
  const tangentX = 2 * (1 - arrowT) * (cpX - fromX) + 2 * arrowT * (toX - cpX);
  const tangentY = 2 * (1 - arrowT) * (cpY - fromY) + 2 * arrowT * (toY - cpY);
  const tangentLen = Math.sqrt(tangentX * tangentX + tangentY * tangentY);
  if (tangentLen < 1) {
    ctx.restore();
    return undefined;
  }

  const arrowSize = highlighted ? 10 : 7;
  const ax = tangentX / tangentLen;
  const ay = tangentY / tangentLen;

  // 略微提前终点以避免覆盖节点圆
  const endX = toX - ax * 4;
  const endY = toY - ay * 4;

  ctx.fillStyle = color;
  ctx.beginPath();
  ctx.moveTo(endX, endY);
  ctx.lineTo(
    endX - arrowSize * ax + arrowSize * 0.4 * ay,
    endY - arrowSize * ay - arrowSize * 0.4 * ax,
  );
  ctx.lineTo(
    endX - arrowSize * ax - arrowSize * 0.4 * ay,
    endY - arrowSize * ay + arrowSize * 0.4 * ax,
  );
  ctx.closePath();
  ctx.fill();

  ctx.restore();

  return { labelX: cpX, labelY: cpY };
}

/** 绘制带渐变填充和阴影的节点圆。 */
export function drawNode(
  ctx: CanvasRenderingContext2D,
  x: number,
  y: number,
  radius: number,
  color: string,
  lightColor: string,
  glowColor: string,
  isCenter: boolean,
  isHovered: boolean,
  alpha: number,
): void {
  ctx.save();
  ctx.globalAlpha = alpha;

  const r = isHovered ? radius * NODE_HOVER_SCALE : radius;

  // 外发光 / 阴影
  if (isCenter || isHovered) {
    ctx.shadowColor = glowColor;
    ctx.shadowBlur = isCenter ? 20 : 14;
  } else {
    ctx.shadowColor = 'rgba(0,0,0,0.12)';
    ctx.shadowBlur = 6;
  }

  // 渐变填充
  const gradient = ctx.createRadialGradient(x - r * 0.3, y - r * 0.3, 0, x, y, r);
  if (isCenter) {
    gradient.addColorStop(0, lightColor);
    gradient.addColorStop(1, color);
  } else {
    gradient.addColorStop(0, 'rgba(255,255,255,0.9)');
    gradient.addColorStop(1, 'rgba(255,255,255,0.4)');
  }

  ctx.beginPath();
  ctx.arc(x, y, r, 0, 2 * Math.PI);
  ctx.fillStyle = gradient;
  ctx.fill();

  // 边框
  ctx.shadowColor = 'transparent';
  ctx.shadowBlur = 0;
  ctx.strokeStyle = isCenter ? color : lightColor;
  ctx.lineWidth = isCenter ? 3 : 1.5;
  if (isHovered) {
    ctx.lineWidth += 1;
  }
  ctx.stroke();

  // 中心节点外圈虚线环
  if (isCenter) {
    ctx.beginPath();
    ctx.arc(x, y, r + 4, 0, 2 * Math.PI);
    ctx.strokeStyle = glowColor;
    ctx.lineWidth = 2;
    ctx.setLineDash([4, 4]);
    ctx.stroke();
    ctx.setLineDash([]);
  }

  ctx.restore();
}

/** 绘制边标签（带背景胶囊）。 */
export function drawEdgeLabel(
  ctx: CanvasRenderingContext2D,
  x: number,
  y: number,
  label: string,
  color: string,
  alpha: number,
): void {
  ctx.save();
  ctx.globalAlpha = alpha * 0.85;

  const display = getEdgeTypeLabel(label);
  ctx.font = '11px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
  const metrics = ctx.measureText(display);
  const textWidth = metrics.width;
  const padding = 6;
  const pillHeight = 18;
  const pillRadius = 9;

  // 背景胶囊
  const pillX = x - textWidth / 2 - padding;
  const pillY = y - pillHeight / 2;

  ctx.fillStyle = color + '18';
  ctx.beginPath();
  ctx.roundRect(pillX, pillY, textWidth + padding * 2, pillHeight, pillRadius);
  ctx.fill();

  ctx.strokeStyle = color + '40';
  ctx.lineWidth = 1;
  ctx.beginPath();
  ctx.roundRect(pillX, pillY, textWidth + padding * 2, pillHeight, pillRadius);
  ctx.stroke();

  // 文本
  ctx.fillStyle = color;
  ctx.textAlign = 'center';
  ctx.textBaseline = 'middle';
  ctx.fillText(display, x, y);

  ctx.restore();
}

/** 在节点下方绘制节点标签。 */
export function drawNodeLabel(
  ctx: CanvasRenderingContext2D,
  x: number,
  y: number,
  radius: number,
  label: string,
  textColor: string,
  isCenter: boolean,
  isHovered: boolean,
): void {
  ctx.save();
  const display = truncateLabel(label);
  const r = isHovered ? radius * NODE_HOVER_SCALE : radius;
  const fontSize = isCenter ? 13 : isHovered ? 12 : 11;
  const fontWeight = isCenter ? '600' : isHovered ? '500' : '400';

  ctx.font = `${fontWeight} ${fontSize}px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`;
  ctx.textAlign = 'center';
  ctx.textBaseline = 'top';
  ctx.fillStyle = textColor;

  if (isCenter || isHovered) {
    ctx.globalAlpha = 1;
  } else {
    ctx.globalAlpha = 0.7;
  }

  ctx.fillText(display, x, y + r + 8);
  ctx.restore();
}
