/**
 * Graph Canvas 渲染 — 边/节点/标签绘制函数
 */

import type { NodePosition } from './graphTypes';
import { degreeToRadius } from './graphLayout';
import {
  getEdgeColor,
  DEFAULT_REL_COLOR,
  NODE_HOVER_SCALE,
  LABEL_MAX_LENGTH,
} from './graphConstants';

// ── Helper 函数 ──

export function getRelColor(label: string) {
  return getEdgeColor(label) || DEFAULT_REL_COLOR;
}

export function getEdgeTypeLabel(label: string): string {
  return label;
}

function truncateLabel(label: string): string {
  return label.length > LABEL_MAX_LENGTH
    ? label.slice(0, LABEL_MAX_LENGTH) + '...'
    : label;
}

// ── 渲染函数 ──

/** 绘制贝塞尔曲线边 + 箭头 */
export function drawCurvedEdge(
  ctx: CanvasRenderingContext2D,
  fromX: number,
  fromY: number,
  toX: number,
  toY: number,
  color: string,
  lineWidth: number,
  highlighted: boolean,
  alpha: number,
) {
  const dx = toX - fromX;
  const dy = toY - fromY;
  const dist = Math.sqrt(dx * dx + dy * dy);
  if (dist < 1) return;

  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 t = 0.95;
  const tangentX = 2 * (1 - t) * (cpX - fromX) + 2 * t * (toX - cpX);
  const tangentY = 2 * (1 - t) * (cpY - fromY) + 2 * t * (toY - cpY);
  const tangentLen = Math.sqrt(tangentX * tangentX + tangentY * tangentY);
  if (tangentLen < 1) {
    ctx.restore();
    return;
  }

  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,
) {
  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,
  _textColor: string,
  alpha: number,
) {
  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,
) {
  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();
}

/** 绘制完整图谱 (edges + nodes + hover tooltip) */
export function drawFullGraph(
  ctx: CanvasRenderingContext2D,
  width: number,
  height: number,
  positions: Map<string, NodePosition>,
  nodes: { id: string; label: string; data: Record<string, unknown> }[],
  edges: { source: string; target: string; label: string }[],
  selectedCenter: string | null,
  hoverState: { nodeId: string | null; x: number; y: number },
  token: {
    colorText: string;
    colorBgContainer: string;
    colorBgElevated: string;
    colorBorderSecondary: string;
  },
  degreeMap: Map<string, number>,
) {
  const textColor = token.colorText;
  const bgColor = token.colorBgContainer;

  ctx.clearRect(0, 0, width, height);
  ctx.fillStyle = bgColor;
  ctx.fillRect(0, 0, width, height);

  if (nodes.length === 0) return;

  // 绘制边 (在节点下方)
  for (const edge of edges) {
    const from = positions.get(edge.source);
    const to = positions.get(edge.target);
    if (!from || !to) continue;

    const colors = getRelColor(edge.label);
    const isHighlighted =
      hoverState.nodeId === edge.source || hoverState.nodeId === edge.target;
    const alpha = hoverState.nodeId ? (isHighlighted ? 1 : 0.15) : 0.7;
    const lw = isHighlighted ? 2.5 : 1.5;

    const labelPos = drawCurvedEdge(
      ctx, from.x, from.y, to.x, to.y,
      colors.base, lw, isHighlighted, alpha,
    );

    if (edge.label && labelPos) {
      const labelAlpha = hoverState.nodeId ? (isHighlighted ? 1 : 0.1) : 0.9;
      drawEdgeLabel(ctx, labelPos.labelX, labelPos.labelY - 10, edge.label, colors.base, textColor, labelAlpha);
    }
  }

  // 绘制节点
  for (const node of nodes) {
    const pos = positions.get(node.id);
    if (!pos) continue;

    const isCenter = node.id === selectedCenter;
    const isHovered = node.id === hoverState.nodeId;
    const degree = degreeMap.get(node.id) || 0;
    const r = degreeToRadius(degree, isCenter);

    let nodeColorBase = '#2563eb';
    let nodeColorLight = '#60a5fa';
    let nodeColorGlow = 'rgba(79,70,229,0.3)';

    if (isCenter) {
      const firstEdge = edges.find((e) => e.source === node.id || e.target === node.id);
      if (firstEdge) {
        const rc = getRelColor(firstEdge.label);
        nodeColorBase = rc.base;
        nodeColorLight = rc.light;
        nodeColorGlow = rc.glow;
      }
    } else {
      const idx = nodes.indexOf(node);
      const pick = getEdgeColor(`_node_${idx}`);
      nodeColorBase = pick.base;
      nodeColorLight = pick.light;
      nodeColorGlow = pick.glow;
    }

    const nodeAlpha = hoverState.nodeId
      ? (isHovered || (hoverState.nodeId && edges.some(
          (e) => (e.source === hoverState.nodeId && e.target === node.id) ||
                 (e.target === hoverState.nodeId && e.source === node.id),
        )) ? 1 : 0.2)
      : 1;

    drawNode(ctx, pos.x, pos.y, r, nodeColorBase, nodeColorLight, nodeColorGlow, isCenter, isHovered, nodeAlpha);
    drawNodeLabel(ctx, pos.x, pos.y, r, node.label, textColor, isCenter, isHovered);
  }

  // Hover tooltip
  if (hoverState.nodeId) {
    const hoveredNode = nodes.find((n) => n.id === hoverState.nodeId);
    if (hoveredNode) {
      const degree = degreeMap.get(hoveredNode.id) || 0;
      const tooltipText = `${hoveredNode.label} (${degree} 条关系)`;
      ctx.save();
      ctx.font = '12px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
      const metrics = ctx.measureText(tooltipText);
      const tw = metrics.width + 16;
      const th = 28;
      const tx = hoverState.x - tw / 2;
      const ty = hoverState.y - 40;

      ctx.fillStyle = token.colorBgElevated;
      ctx.shadowColor = 'rgba(0,0,0,0.15)';
      ctx.shadowBlur = 8;
      ctx.beginPath();
      ctx.roundRect(tx, ty, tw, th, 6);
      ctx.fill();

      ctx.shadowBlur = 0;
      ctx.fillStyle = token.colorText;
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
      ctx.fillText(tooltipText, hoverState.x, ty + th / 2);
      ctx.restore();
    }
  }
}
