import { describe, it, expect } from "vitest";
import {
  graphNodeToFlowNode,
  graphEdgeToFlowEdge,
  graphToFlow,
  flowNodeToGraphNode,
  flowEdgeToGraphEdge,
  flowToGraph,
} from "./graph-converter";
import type {
  DiagramNode,
  DiagramEdge,
  GraphData,
} from "../types/graph";

describe("graphNodeToFlowNode", () => {
  it("should convert a basic node with position", () => {
    const node: DiagramNode = {
      id: "n1",
      type: "flow:process",
      label: "Start",
      position: { x: 100, y: 200 },
    };
    const result = graphNodeToFlowNode(node);
    expect(result).toEqual({
      id: "n1",
      type: "flowProcess",
      position: { x: 100, y: 200 },
      data: { ...node, label: "Start" },
    });
  });

  it("should use default position when node has no position", () => {
    const node: DiagramNode = {
      id: "n2",
      type: "bpmn:activity",
      label: "Task A",
    };
    const result = graphNodeToFlowNode(node);
    expect(result.position).toEqual({ x: 0, y: 0 });
  });

  it("should preserve all node data in data field", () => {
    const node: DiagramNode = {
      id: "n3",
      type: "er:entity",
      label: "Users",
      columns: [
        { name: "id", type: "uuid", isPrimaryKey: true },
        { name: "name", type: "text" },
      ],
    };
    const result = graphNodeToFlowNode(node);
    expect(result.data.columns).toEqual(node.columns);
    expect(result.data.type).toBe("er:entity");
  });
});

describe("graphEdgeToFlowEdge", () => {
  it("should convert from/to to source/target", () => {
    const edge: DiagramEdge = {
      id: "e1",
      from: "n1",
      to: "n2",
      label: "connects",
    };
    const result = graphEdgeToFlowEdge(edge);
    expect(result).toEqual({
      id: "e1",
      source: "n1",
      target: "n2",
      label: "connects",
      type: "default",
      data: { ...edge },
    });
  });

  it("should handle edges without labels", () => {
    const edge: DiagramEdge = { id: "e2", from: "a", to: "b" };
    const result = graphEdgeToFlowEdge(edge);
    expect(result.label).toBeUndefined();
  });

  it("should preserve E-R cardinality", () => {
    const edge: DiagramEdge = {
      id: "e3",
      from: "users",
      to: "orders",
      cardinality: "1:N",
      type: "inheritance",
    };
    const result = graphEdgeToFlowEdge(edge);
    expect(result.data?.cardinality).toBe("1:N");
  });
});

describe("graphToFlow", () => {
  it("should convert full GraphData to flow format", () => {
    const data: GraphData = {
      nodes: [
        { id: "n1", type: "flow:process", label: "A", position: { x: 0, y: 0 } },
        { id: "n2", type: "flow:decision", label: "B", position: { x: 100, y: 100 } },
      ],
      edges: [
        { id: "e1", from: "n1", to: "n2", label: "yes" },
      ],
    };
    const result = graphToFlow(data);
    expect(result.nodes).toHaveLength(2);
    expect(result.edges).toHaveLength(1);
    expect(result.nodes[0]!.id).toBe("n1");
    expect(result.edges[0]!.source).toBe("n1");
    expect(result.edges[0]!.target).toBe("n2");
  });

  it("should handle empty graph data", () => {
    const data: GraphData = { nodes: [], edges: [] };
    const result = graphToFlow(data);
    expect(result.nodes).toEqual([]);
    expect(result.edges).toEqual([]);
  });

  it("should handle all 6 diagram types", () => {
    const diagramTypes = [
      "bpmn:activity",
      "er:entity",
      "org:person",
      "arch:service",
      "seq:participant",
      "flow:process",
    ];
    const nodes: DiagramNode[] = diagramTypes.map((type, i) => ({
      id: `n${i}`,
      type,
      label: `Node ${i}`,
    }));
    const result = graphToFlow({ nodes, edges: [] });
    expect(result.nodes).toHaveLength(6);
    // bpmn: prefix resolves to BPMN node type even without diagramType context
    expect(result.nodes[0]!.type).toBe("bpmnActivity");
    // er: prefix resolves to E-R node type even without diagramType context
    expect(result.nodes[1]!.type).toBe("erEntity");
    // org: prefix resolves to org chart node type even without diagramType context
    expect(result.nodes[2]!.type).toBe("orgchartPerson");
    // arch: prefix resolves to architecture node type even without diagramType context
    expect(result.nodes[3]!.type).toBe("archService");
    // seq: prefix resolves to sequence node type even without diagramType context
    expect(result.nodes[4]!.type).toBe("seqParticipant");
    // flow: prefix resolves to flowchart node type even without diagramType context
    expect(result.nodes[5]!.type).toBe("flowProcess");
  });

  it("should resolve architecture node types when diagramType is architecture", () => {
    const data: GraphData = {
      meta: {
        version: "1.0",
        title: "Architecture Test",
        diagramType: "architecture",
      },
      nodes: [
        { id: "n1", type: "service", label: "API" },
        { id: "n2", type: "arch:database", label: "DB" },
        { id: "n3", type: "arch:queue", label: "Queue" },
        { id: "n4", type: "arch:loadbalancer", label: "LB" },
        { id: "n5", type: "arch:external", label: "Stripe" },
      ],
      edges: [],
    };
    const result = graphToFlow(data);
    expect(result.nodes[0]!.type).toBe("archService");
    expect(result.nodes[1]!.type).toBe("archDatabase");
    expect(result.nodes[2]!.type).toBe("archQueue");
    expect(result.nodes[3]!.type).toBe("archLoadBalancer");
    expect(result.nodes[4]!.type).toBe("archExternal");
  });

  it("should resolve architecture edge types when diagramType is architecture", () => {
    const data: GraphData = {
      meta: {
        version: "1.0",
        title: "Architecture Edge Test",
        diagramType: "architecture",
      },
      nodes: [
        { id: "svc", type: "arch:service", label: "API" },
        { id: "db", type: "arch:database", label: "DB" },
      ],
      edges: [
        { id: "e1", from: "svc", to: "db", type: "sync", label: "PostgreSQL" },
        { id: "e2", from: "svc", to: "db", type: "async", label: "AMQP" },
        { id: "e3", from: "svc", to: "db" },
      ],
    };
    const result = graphToFlow(data);
    expect(result.edges[0]!.type).toBe("archConnection");
    expect(result.edges[1]!.type).toBe("archConnection");
    expect(result.edges[2]!.type).toBe("archConnection");
  });

  it("should use flat layout for architecture diagrams (no container nodes)", () => {
    const data: GraphData = {
      meta: {
        version: "1.0",
        title: "Architecture Flat Layout",
        diagramType: "architecture",
      },
      nodes: [
        { id: "lb", type: "arch:loadbalancer", label: "LB" },
        { id: "svc1", type: "arch:service", label: "Service 1" },
        { id: "svc2", type: "arch:service", label: "Service 2" },
        { id: "db", type: "arch:database", label: "DB" },
      ],
      edges: [
        { id: "e1", from: "lb", to: "svc1", type: "sync", label: "HTTP" },
        { id: "e2", from: "lb", to: "svc2", type: "sync", label: "HTTP" },
        { id: "e3", from: "svc1", to: "db", type: "sync", label: "PostgreSQL" },
      ],
    };
    const result = graphToFlow(data);
    expect(result.nodes).toHaveLength(4);
    expect(result.edges).toHaveLength(3);
  });

  it("should resolve E-R node types when diagramType is er", () => {
    const data: GraphData = {
      meta: {
        version: "1.0",
        title: "E-R Test",
        diagramType: "er",
      },
      nodes: [
        { id: "n1", type: "entity", label: "Users" },
        { id: "n2", type: "er:entity", label: "Orders" },
      ],
      edges: [],
    };
    const result = graphToFlow(data);
    expect(result.nodes[0]!.type).toBe("erEntity");
    expect(result.nodes[1]!.type).toBe("erEntity");
  });

  it("should resolve E-R edge types when diagramType is er", () => {
    const data: GraphData = {
      meta: {
        version: "1.0",
        title: "E-R Edge Test",
        diagramType: "er",
      },
      nodes: [
        { id: "users", type: "er:entity", label: "Users" },
        { id: "orders", type: "er:entity", label: "Orders" },
      ],
      edges: [
        { id: "e1", from: "users", to: "orders", type: "relationship", cardinality: "1:N" },
        { id: "e2", from: "users", to: "orders" },
      ],
    };
    const result = graphToFlow(data);
    expect(result.edges[0]!.type).toBe("erRelationship");
    expect(result.edges[1]!.type).toBe("erRelationship");
    expect(result.edges[0]!.data?.cardinality).toBe("1:N");
  });

  it("should use flat layout for E-R diagrams (no container nodes)", () => {
    const data: GraphData = {
      meta: {
        version: "1.0",
        title: "E-R Flat Layout",
        diagramType: "er",
      },
      nodes: [
        { id: "users", type: "er:entity", label: "Users", columns: [{ name: "id", type: "uuid", isPrimaryKey: true }] },
        { id: "orders", type: "er:entity", label: "Orders" },
      ],
      edges: [{ id: "e1", from: "users", to: "orders", cardinality: "1:N" }],
    };
    const result = graphToFlow(data);
    // E-R uses flat layout — no pool/lane/group container nodes
    expect(result.nodes).toHaveLength(2);
    expect(result.nodes.every((n) => n.type === "erEntity")).toBe(true);
  });

  it("should produce correct flat structure for E-R M:N with junction table (AC #3)", () => {
    const data: GraphData = {
      meta: {
        version: "1.0",
        title: "M:N Junction Table",
        diagramType: "er",
      },
      nodes: [
        {
          id: "students",
          type: "er:entity",
          label: "Students",
          columns: [
            { name: "id", type: "uuid", isPrimaryKey: true },
            { name: "name", type: "text" },
          ],
        },
        {
          id: "courses",
          type: "er:entity",
          label: "Courses",
          columns: [
            { name: "id", type: "uuid", isPrimaryKey: true },
            { name: "title", type: "text" },
          ],
        },
        {
          id: "enrollments",
          type: "er:entity",
          label: "Enrollments",
          columns: [
            { name: "student_id", type: "uuid", isForeignKey: true },
            { name: "course_id", type: "uuid", isForeignKey: true },
          ],
        },
      ],
      edges: [
        { id: "e1", from: "students", to: "enrollments", cardinality: "1:N" },
        { id: "e2", from: "courses", to: "enrollments", cardinality: "1:N" },
      ],
    };
    const result = graphToFlow(data);
    // All 3 entities are flat nodes (no container hierarchy)
    expect(result.nodes).toHaveLength(3);
    expect(result.nodes.every((n) => n.type === "erEntity")).toBe(true);
    // Junction table has edges connecting it to both parent entities
    expect(result.edges).toHaveLength(2);
    expect(result.edges[0]!.type).toBe("erRelationship");
    expect(result.edges[1]!.type).toBe("erRelationship");
    // Junction table node preserves FK columns for ELK height computation
    const junctionNode = result.nodes.find((n) => n.id === "enrollments");
    expect((junctionNode!.data as unknown as DiagramNode).columns).toHaveLength(2);
  });

  it("should resolve org chart node types when diagramType is orgchart", () => {
    const data: GraphData = {
      meta: {
        version: "1.0",
        title: "Org Chart Test",
        diagramType: "orgchart",
      },
      nodes: [
        { id: "n1", type: "person", label: "Alice", tag: "CEO" },
        { id: "n2", type: "org:person", label: "Bob", tag: "CTO" },
      ],
      edges: [],
    };
    const result = graphToFlow(data);
    expect(result.nodes[0]!.type).toBe("orgchartPerson");
    expect(result.nodes[1]!.type).toBe("orgchartPerson");
  });

  it("should resolve org chart edge types when diagramType is orgchart", () => {
    const data: GraphData = {
      meta: {
        version: "1.0",
        title: "Org Chart Edge Test",
        diagramType: "orgchart",
      },
      nodes: [
        { id: "ceo", type: "org:person", label: "Alice", tag: "CEO" },
        { id: "cto", type: "org:person", label: "Bob", tag: "CTO" },
      ],
      edges: [
        { id: "e1", from: "ceo", to: "cto", type: "hierarchy" },
        { id: "e2", from: "ceo", to: "cto" },
      ],
    };
    const result = graphToFlow(data);
    expect(result.edges[0]!.type).toBe("orgchartHierarchy");
    expect(result.edges[1]!.type).toBe("orgchartHierarchy");
  });

  it("should resolve sequence node types when diagramType is sequence", () => {
    const data: GraphData = {
      meta: {
        version: "1.0",
        title: "Sequence Test",
        diagramType: "sequence",
      },
      nodes: [
        { id: "n1", type: "participant", label: "Client" },
        { id: "n2", type: "seq:participant", label: "Server" },
        { id: "n3", type: "seq:fragment", label: "alt" },
      ],
      edges: [],
    };
    const result = graphToFlow(data);
    expect(result.nodes[0]!.type).toBe("seqParticipant");
    expect(result.nodes[1]!.type).toBe("seqParticipant");
    expect(result.nodes[2]!.type).toBe("seqFragment");
  });

  it("should resolve sequence edge types when diagramType is sequence", () => {
    const data: GraphData = {
      meta: {
        version: "1.0",
        title: "Sequence Edge Test",
        diagramType: "sequence",
      },
      nodes: [
        { id: "client", type: "seq:participant", label: "Client" },
        { id: "server", type: "seq:participant", label: "Server" },
      ],
      edges: [
        { id: "e1", from: "client", to: "server", type: "sync", label: "POST /login" },
        { id: "e2", from: "server", to: "client", type: "async", label: "enqueue" },
        { id: "e3", from: "server", to: "client", type: "return", label: "200 OK" },
        { id: "e4", from: "client", to: "server" },
      ],
    };
    const result = graphToFlow(data);
    expect(result.edges[0]!.type).toBe("seqSync");
    expect(result.edges[1]!.type).toBe("seqAsync");
    expect(result.edges[2]!.type).toBe("seqReturn");
    expect(result.edges[3]!.type).toBe("seqSync"); // default
  });

  it("should use flat layout for sequence diagrams (no container nodes)", () => {
    const data: GraphData = {
      meta: {
        version: "1.0",
        title: "Sequence Flat Layout",
        diagramType: "sequence",
      },
      nodes: [
        { id: "client", type: "seq:participant", label: "Client", lifeline: true },
        { id: "server", type: "seq:participant", label: "Server", lifeline: true },
        { id: "alt-1", type: "seq:fragment", label: "alt", tag: "[valid]", group: "m2" },
      ],
      edges: [
        { id: "m1", from: "client", to: "server", type: "sync", label: "request" },
        { id: "m2", from: "server", to: "client", type: "return", label: "response" },
      ],
    };
    const result = graphToFlow(data);
    expect(result.nodes).toHaveLength(3);
    expect(result.edges).toHaveLength(2);
  });

  it("should resolve flowchart node types when diagramType is flowchart", () => {
    const data: GraphData = {
      meta: {
        version: "1.0",
        title: "Flowchart Test",
        diagramType: "flowchart",
      },
      nodes: [
        { id: "n1", type: "process", label: "Step 1" },
        { id: "n2", type: "flow:decision", label: "Check?" },
        { id: "n3", type: "flow:terminal", label: "Start", tag: "start" },
        { id: "n4", type: "flow:io", label: "Read Input" },
        { id: "n5", type: "flow:subprocess", label: "Validate" },
      ],
      edges: [],
    };
    const result = graphToFlow(data);
    expect(result.nodes[0]!.type).toBe("flowProcess");
    expect(result.nodes[1]!.type).toBe("flowDecision");
    expect(result.nodes[2]!.type).toBe("flowTerminal");
    expect(result.nodes[3]!.type).toBe("flowIo");
    expect(result.nodes[4]!.type).toBe("flowSubprocess");
  });

  it("should resolve flowchart edge types when diagramType is flowchart", () => {
    const data: GraphData = {
      meta: {
        version: "1.0",
        title: "Flowchart Edge Test",
        diagramType: "flowchart",
      },
      nodes: [
        { id: "start", type: "flow:terminal", label: "Start" },
        { id: "step1", type: "flow:process", label: "Step 1" },
      ],
      edges: [
        { id: "e1", from: "start", to: "step1", type: "sequence" },
        { id: "e2", from: "start", to: "step1" },
      ],
    };
    const result = graphToFlow(data);
    expect(result.edges[0]!.type).toBe("flowEdge");
    expect(result.edges[1]!.type).toBe("flowEdge");
  });

  it("should use flat layout for flowchart diagrams (no container nodes)", () => {
    const data: GraphData = {
      meta: {
        version: "1.0",
        title: "Flowchart Flat Layout",
        diagramType: "flowchart",
      },
      nodes: [
        { id: "start", type: "flow:terminal", label: "Start", tag: "start" },
        { id: "step1", type: "flow:process", label: "Process" },
        { id: "check", type: "flow:decision", label: "OK?" },
        { id: "end", type: "flow:terminal", label: "End", tag: "end" },
      ],
      edges: [
        { id: "e1", from: "start", to: "step1" },
        { id: "e2", from: "step1", to: "check" },
        { id: "e3", from: "check", to: "end", label: "Yes" },
      ],
    };
    const result = graphToFlow(data);
    expect(result.nodes).toHaveLength(4);
    expect(result.edges).toHaveLength(3);
  });

  it("should use flat layout for org chart diagrams (no container nodes)", () => {
    const data: GraphData = {
      meta: {
        version: "1.0",
        title: "Org Chart Flat Layout",
        diagramType: "orgchart",
      },
      nodes: [
        { id: "ceo", type: "org:person", label: "Alice", tag: "CEO", group: "Executive" },
        { id: "cto", type: "org:person", label: "Bob", tag: "CTO", group: "Technology" },
        { id: "dev", type: "org:person", label: "Carol", tag: "Developer", group: "Technology" },
      ],
      edges: [
        { id: "e1", from: "ceo", to: "cto" },
        { id: "e2", from: "cto", to: "dev" },
      ],
    };
    const result = graphToFlow(data);
    // Org chart uses flat layout — no pool/lane/group container nodes
    expect(result.nodes).toHaveLength(3);
    expect(result.nodes.every((n) => n.type === "orgchartPerson")).toBe(true);
    expect(result.edges).toHaveLength(2);
  });

  it("should resolve BPMN node types when diagramType is bpmn", () => {
    const data: GraphData = {
      meta: {
        version: "1.0",
        title: "BPMN Test",
        diagramType: "bpmn",
      },
      nodes: [
        { id: "n1", type: "activity", label: "Task" },
        { id: "n2", type: "bpmn:gateway-exclusive", label: "Decision?" },
        { id: "n3", type: "start-event", label: "Start" },
      ],
      edges: [],
    };
    const result = graphToFlow(data);
    expect(result.nodes[0]!.type).toBe("bpmnActivity");
    expect(result.nodes[1]!.type).toBe("bpmnGateway");
    expect(result.nodes[2]!.type).toBe("bpmnStartEvent");
  });

  it("should resolve BPMN edge types when diagramType is bpmn", () => {
    const data: GraphData = {
      meta: {
        version: "1.0",
        title: "BPMN Edge Test",
        diagramType: "bpmn",
      },
      nodes: [
        { id: "a", type: "activity", label: "A" },
        { id: "b", type: "activity", label: "B" },
        { id: "c", type: "activity", label: "C" },
      ],
      edges: [
        { id: "e1", from: "a", to: "b", type: "sequence" },
        { id: "e2", from: "a", to: "c", type: "message" },
        { id: "e3", from: "b", to: "c", type: "association" },
      ],
    };
    const result = graphToFlow(data);
    expect(result.edges[0]!.type).toBe("bpmnSequence");
    expect(result.edges[1]!.type).toBe("bpmnMessage");
    expect(result.edges[2]!.type).toBe("bpmnAssociation");
  });

  it("should create pool and lane nodes for BPMN with pools", () => {
    const data: GraphData = {
      meta: {
        version: "1.0",
        title: "Pool Test",
        diagramType: "bpmn",
      },
      pools: [
        {
          id: "pool1",
          label: "Pool",
          lanes: [{ id: "lane1", label: "Lane 1" }],
        },
      ],
      nodes: [{ id: "n1", type: "activity", label: "Task", lane: "lane1" }],
      edges: [],
    };
    const result = graphToFlow(data);
    // pool + lane + content node = 3
    expect(result.nodes).toHaveLength(3);
    const poolNode = result.nodes.find((n) => n.id === "pool1");
    expect(poolNode?.type).toBe("bpmnPool");
    const laneNode = result.nodes.find((n) => n.id === "lane1");
    expect(laneNode?.type).toBe("bpmnLane");
    expect(laneNode?.parentId).toBe("pool1");
    const contentNode = result.nodes.find((n) => n.id === "n1");
    expect(contentNode?.parentId).toBe("lane1");
  });

  it("should filter pool/lane nodes from flowToGraph output", () => {
    const nodes = [
      { id: "pool1", type: "bpmnPool", position: { x: 0, y: 0 }, data: { label: "Pool" } },
      { id: "lane1", type: "bpmnLane", position: { x: 0, y: 0 }, data: { label: "Lane" } },
      { id: "n1", type: "bpmnActivity", position: { x: 10, y: 20 }, data: { type: "bpmn:activity", label: "Task" } },
    ];
    const result = flowToGraph(nodes, []);
    expect(result.nodes).toHaveLength(1);
    expect(result.nodes[0]!.id).toBe("n1");
  });

  it("should preserve pools in flowToGraph roundtrip", () => {
    const nodes = [
      { id: "pool1", type: "bpmnPool", position: { x: 0, y: 0 }, data: { label: "Main Pool" } },
      { id: "lane1", type: "bpmnLane", position: { x: 0, y: 0 }, parentId: "pool1", data: { label: "Lane A" } },
      { id: "lane2", type: "bpmnLane", position: { x: 0, y: 0 }, parentId: "pool1", data: { label: "Lane B" } },
      { id: "n1", type: "bpmnActivity", position: { x: 10, y: 20 }, data: { type: "bpmn:activity", label: "Task" } },
    ];
    const result = flowToGraph(nodes, []);
    expect(result.pools).toBeDefined();
    expect(result.pools).toHaveLength(1);
    expect(result.pools![0]!.id).toBe("pool1");
    expect(result.pools![0]!.label).toBe("Main Pool");
    expect(result.pools![0]!.lanes).toHaveLength(2);
    expect(result.pools![0]!.lanes[0]!.id).toBe("lane1");
  });

  it("should preserve groups in flowToGraph roundtrip", () => {
    const nodes = [
      { id: "g1", type: "bpmnGroup", position: { x: 0, y: 0 }, data: { label: "Group 1", color: "#ff0000" } },
      { id: "n1", type: "bpmnActivity", position: { x: 10, y: 20 }, data: { type: "bpmn:activity", label: "Task" } },
    ];
    const result = flowToGraph(nodes, []);
    expect(result.groups).toBeDefined();
    expect(result.groups).toHaveLength(1);
    expect(result.groups![0]!.id).toBe("g1");
    expect(result.groups![0]!.label).toBe("Group 1");
    expect(result.groups![0]!.color).toBe("#ff0000");
    expect(result.nodes).toHaveLength(1);
  });
});

describe("flowNodeToGraphNode", () => {
  it("should convert flow node back to graph node", () => {
    const flowNode = {
      id: "n1",
      type: "default",
      position: { x: 50, y: 75 },
      data: {
        id: "n1",
        type: "bpmn:activity",
        label: "Task",
        lane: "lane1",
      },
    };
    const result = flowNodeToGraphNode(flowNode);
    expect(result.id).toBe("n1");
    expect(result.type).toBe("bpmn:activity");
    expect(result.label).toBe("Task");
    expect(result.position).toEqual({ x: 50, y: 75 });
    expect(result.lane).toBe("lane1");
  });

  it("should default to flow:process when type is missing", () => {
    const flowNode = {
      id: "n1",
      type: "default",
      position: { x: 0, y: 0 },
      data: { label: "No type" },
    };
    const result = flowNodeToGraphNode(flowNode);
    expect(result.type).toBe("flow:process");
  });
});

describe("flowEdgeToGraphEdge", () => {
  it("should convert source/target back to from/to", () => {
    const flowEdge = {
      id: "e1",
      source: "n1",
      target: "n2",
      label: "Yes",
      type: "default",
      data: { type: "sequence", color: "#ff0000" },
    };
    const result = flowEdgeToGraphEdge(flowEdge);
    expect(result.from).toBe("n1");
    expect(result.to).toBe("n2");
    expect(result.label).toBe("Yes");
    expect(result.type).toBe("sequence");
    expect(result.color).toBe("#ff0000");
  });

  it("should handle edges with no data", () => {
    const flowEdge = {
      id: "e2",
      source: "a",
      target: "b",
    };
    const result = flowEdgeToGraphEdge(flowEdge);
    expect(result.from).toBe("a");
    expect(result.to).toBe("b");
    expect(result.type).toBeUndefined();
  });
});

describe("flowToGraph", () => {
  it("should convert full flow state back to GraphData", () => {
    const nodes = [
      {
        id: "n1",
        type: "default",
        position: { x: 10, y: 20 },
        data: { type: "flow:process", label: "Step 1" },
      },
    ];
    const edges = [
      {
        id: "e1",
        source: "n1",
        target: "n2",
        label: "next",
        data: { type: "sequence" },
      },
    ];
    const meta = {
      version: "1.0",
      title: "Test",
      diagramType: "flowchart" as const,
    };
    const result = flowToGraph(nodes, edges, meta);
    expect(result.meta).toEqual(meta);
    expect(result.nodes).toHaveLength(1);
    expect(result.edges).toHaveLength(1);
    expect(result.nodes[0]!.type).toBe("flow:process");
    expect(result.edges[0]!.from).toBe("n1");
  });

  it("should roundtrip: graphToFlow -> flowToGraph preserves data", () => {
    const original: GraphData = {
      meta: {
        version: "1.0",
        title: "Roundtrip Test",
        diagramType: "er",
      },
      nodes: [
        {
          id: "users",
          type: "er:entity",
          label: "Users",
          position: { x: 0, y: 0 },
          columns: [
            { name: "id", type: "uuid", isPrimaryKey: true },
            { name: "email", type: "varchar" },
          ],
        },
        {
          id: "orders",
          type: "er:entity",
          label: "Orders",
          position: { x: 200, y: 0 },
        },
      ],
      edges: [
        {
          id: "e1",
          from: "users",
          to: "orders",
          label: "has",
          cardinality: "1:N",
        },
      ],
    };

    const flow = graphToFlow(original);
    const roundtripped = flowToGraph(flow.nodes, flow.edges, original.meta);

    expect(roundtripped.meta).toEqual(original.meta);
    expect(roundtripped.nodes).toHaveLength(2);
    expect(roundtripped.edges).toHaveLength(1);
    expect(roundtripped.nodes[0]!.type).toBe("er:entity");
    expect(roundtripped.nodes[0]!.columns).toEqual(original.nodes[0]!.columns);
    expect(roundtripped.edges[0]!.from).toBe("users");
    expect(roundtripped.edges[0]!.to).toBe("orders");
    expect(roundtripped.edges[0]!.cardinality).toBe("1:N");
  });
});
