import type { Node, Edge } from "@xyflow/react";
import type { DiagramNode, DiagramEdge, GraphData } from "../types/graph";

export function graphNodeToFlowNode(node: DiagramNode): Node {
  return {
    id: node.id,
    type: "default",
    position: node.position ?? { x: 0, y: 0 },
    data: {
      ...node,
      label: node.label,
    },
  };
}

export function graphEdgeToFlowEdge(edge: DiagramEdge): Edge {
  return {
    id: edge.id,
    source: edge.from,
    target: edge.to,
    label: edge.label,
    type: "default",
    data: { ...edge },
  };
}

export function graphToFlow(data: GraphData): { nodes: Node[]; edges: Edge[] } {
  return {
    nodes: (data.nodes ?? []).map(graphNodeToFlowNode),
    edges: (data.edges ?? []).map(graphEdgeToFlowEdge),
  };
}

export function flowNodeToGraphNode(node: Node): DiagramNode {
  const data = node.data as unknown as DiagramNode & { label: string };
  return {
    id: node.id,
    type: data.type ?? "flow:process",
    label: data.label,
    position: node.position,
    ...(data.tag !== undefined && { tag: data.tag }),
    ...(data.icon !== undefined && { icon: data.icon }),
    ...(data.color !== undefined && { color: data.color }),
    ...(data.w !== undefined && { w: data.w }),
    ...(data.lane !== undefined && { lane: data.lane }),
    ...(data.group !== undefined && { group: data.group }),
    ...(data.columns !== undefined && { columns: data.columns }),
    ...(data.lifeline !== undefined && { lifeline: data.lifeline }),
    ...(data.parentId !== undefined && { parentId: data.parentId }),
  };
}

export function flowEdgeToGraphEdge(edge: Edge): DiagramEdge {
  const data = edge.data as unknown as DiagramEdge | undefined;
  return {
    id: edge.id,
    from: edge.source,
    to: edge.target,
    label: typeof edge.label === "string" ? edge.label : undefined,
    type: data?.type,
    color: data?.color,
    cardinality: data?.cardinality,
  };
}

export function flowToGraph(
  nodes: Node[],
  edges: Edge[],
  meta?: GraphData["meta"],
): GraphData {
  return {
    meta,
    nodes: nodes.map(flowNodeToGraphNode),
    edges: edges.map(flowEdgeToGraphEdge),
  };
}
