import type {
  Node,
  Edge,
  GraphNode,
  GraphEdge,
  RawTriplet,
  GraphTriplet,
} from "./type";

export function toGraphNode(node: Node): GraphNode {
  const primaryLabel =
    node.labels?.find((label) => label != "Entity") || "Entity";

  return {
    id: node.uuid,
    value: node.name,
    uuid: node.uuid,
    name: node.name,
    createdAt: node.createdAt,
    attributes: node.attributes,
    summary: node.summary,
    labels: node.labels,
    primaryLabel,
    clusterId: node?.clusterId, // Extract cluster ID from attributes
  };
}

export function toGraphEdge(edge: Edge): GraphEdge {
  return {
    id: edge.uuid,
    value: edge.type,
    ...edge,
  };
}

export function toGraphTriplet(triplet: RawTriplet): GraphTriplet {
  return {
    source: toGraphNode(triplet.sourceNode),
    relation: toGraphEdge(triplet.edge),
    target: toGraphNode(triplet.targetNode),
  };
}

export function toGraphTriplets(triplets: RawTriplet[]): GraphTriplet[] {
  return triplets.map(toGraphTriplet);
}

export function drawRoundRect(
  ctx: CanvasRenderingContext2D,
  x: number,
  y: number,
  width: number,
  height: number,
  radius: number,
): void {
  ctx.beginPath();
  ctx.moveTo(x + radius, y);
  ctx.lineTo(x + width - radius, y);
  ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
  ctx.lineTo(x + width, y + height - radius);
  ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
  ctx.lineTo(x + radius, y + height);
  ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
  ctx.lineTo(x, y + radius);
  ctx.quadraticCurveTo(x, y, x + radius, y);
  ctx.closePath();
}

const TEXT_COLOR = "#000000";

export function drawHover(
  context: CanvasRenderingContext2D,
  data: any,
  settings: any,
) {
  const size = settings.labelSize;
  const font = settings.labelFont;
  const weight = settings.labelWeight;
  const subLabelSize = size - 2;

  const label = data.label;
  const subLabel = data.tag !== "unknown" ? data.tag : "";
  const entityLabel = data.nodeData.attributes.nodeType;

  // Simulate the --shadow-1 Tailwind shadow:
  // lch(0 0 0 / 0.022) 0px 3px 6px -2px, lch(0 0 0 / 0.044) 0px 1px 1px;
  // Canvas only supports a single shadow, so we approximate with the stronger one.
  // lch(0 0 0 / 0.044) is roughly rgba(0,0,0,0.044)
  context.beginPath();
  context.fillStyle = "#fff";
  context.shadowOffsetX = 0;
  context.shadowOffsetY = 1;
  context.shadowBlur = 1;
  context.shadowColor = "rgba(0,0,0,0.044)";

  context.font = `${weight} ${size}px ${font}`;
  const labelWidth = context.measureText(label).width;
  context.font = `${weight} ${subLabelSize}px ${font}`;
  const subLabelWidth = subLabel ? context.measureText(subLabel).width : 0;
  context.font = `${weight} ${subLabelSize}px ${font}`;
  const entityLabelWidth = entityLabel
    ? context.measureText(entityLabel).width
    : 0;

  const textWidth = Math.max(labelWidth, subLabelWidth, entityLabelWidth);

  const x = Math.round(data.x);
  const y = Math.round(data.y);
  const w = Math.round(textWidth + size / 2 + data.size + 3);
  const hLabel = Math.round(size / 2 + 4);
  const hSubLabel = subLabel ? Math.round(subLabelSize / 2 + 9) : 0;
  const hentityLabel = Math.round(subLabelSize / 2 + 9);

  drawRoundRect(
    context,
    x,
    y - hSubLabel - 12,
    w,
    hentityLabel + hLabel + hSubLabel + 12,
    5,
  );
  context.closePath();
  context.fill();

  // Remove shadow for text
  context.shadowOffsetX = 0;
  context.shadowOffsetY = 0;
  context.shadowBlur = 0;
  context.shadowColor = "transparent";

  // And finally we draw the labels
  context.fillStyle = TEXT_COLOR;
  context.font = `${weight} ${size}px ${font}`;
  context.fillText(label, data.x + data.size + 3, data.y + size / 3);

  if (subLabel) {
    context.fillStyle = TEXT_COLOR;
    context.font = `${weight} ${subLabelSize}px ${font}`;
    context.fillText(
      subLabel,
      data.x + data.size + 3,
      data.y - (2 * size) / 3 - 2,
    );
  }

  context.fillStyle = data.color;
  context.font = `${weight} ${subLabelSize}px ${font}`;
  context.fillText(
    entityLabel,
    data.x + data.size + 3,
    data.y + size / 3 + 3 + subLabelSize,
  );
}
