import type { NetworkNode } from "@/api/client";
import { statusRGBA, rgbaToHex, type StatusColors } from "./graphColors";

export interface GraphNode {
  id: string;
  name: string;
  entry: NetworkNode;
  type: "self" | "peer" | "interface";
  color: string;
  size: number;
  cluster?: string;
  x?: number;
  y?: number;
  z?: number;
}

export interface GraphLink {
  source: string;
  target: string;
}

export interface GraphData {
  nodes: GraphNode[];
  links: GraphLink[];
  clusterNames: string[];
}

function findParentIface(
  entry: NetworkNode,
  interfaces: NetworkNode[],
  peerIndex: number,
): NetworkNode | undefined {
  if (entry.interface) {
    const iface = interfaces.find(i => i.name === entry.interface);
    if (iface) return iface;
  }
  if (interfaces.length > 0) return interfaces[peerIndex % interfaces.length];
  return undefined;
}

export function buildGraphData(
  rawNodes: NetworkNode[],
  prevPositions: Map<string, { x: number; y: number; z: number }>,
  theme: StatusColors,
): GraphData {
  const interfaces = rawNodes
    .filter(e => e.type === "interface")
    .sort((a, b) => a.name.localeCompare(b.name));
  const selfNode = rawNodes.find(e => e.is_self && e.type !== "interface");
  const peers = rawNodes.filter(e => !e.is_self && e.type !== "interface");

  const nodes: GraphNode[] = [];
  const links: GraphLink[] = [];

  // Add interface nodes
  for (const iface of interfaces) {
    const prev = prevPositions.get(iface.hash);
    nodes.push({
      id: iface.hash,
      name: iface.name,
      entry: iface,
      type: "interface",
      color: rgbaToHex(theme.stale),
      size: 2,
      ...(prev ? { x: prev.x, y: prev.y, z: prev.z } : {}),
    });
  }

  // Add self node
  if (selfNode) {
    const prev = prevPositions.get(selfNode.hash);
    nodes.push({
      id: selfNode.hash,
      name: selfNode.name,
      entry: selfNode,
      type: "self",
      color: "#ffffff",
      size: 2,
      ...(prev ? { x: prev.x, y: prev.y, z: prev.z } : {}),
    });
  }

  // Add peer nodes + links to parent interface
  peers.forEach((peer, i) => {
    const prev = prevPositions.get(peer.hash);
    const parentIface = findParentIface(peer, interfaces, i);
    nodes.push({
      id: peer.hash,
      name: peer.name,
      entry: peer,
      type: "peer",
      color: rgbaToHex(statusRGBA(peer, theme)),
      size: 2,
      cluster: parentIface?.name,
      ...(prev ? { x: prev.x, y: prev.y, z: prev.z } : {}),
    });

    if (parentIface) {
      links.push({ source: parentIface.hash, target: peer.hash });
    }
  });

  const clusterNames = interfaces.map(i => i.name);

  return { nodes, links, clusterNames };
}
