import { describe, it, expect } from 'vitest';
import type { Edge } from '@xyflow/react';
import { getReconnectionEdge, reconnectEdgesAfterDeletion } from './edgeReconnection';

describe('edgeReconnection', () => {
  describe('getReconnectionEdge', () => {
    it('returns reconnection edge for simple linear case (1 in, 1 out)', () => {
      const edges: Edge[] = [
        { id: 'e1', source: 'node1', target: 'node2', type: 'smoothstep' },
        { id: 'e2', source: 'node2', target: 'node3', type: 'smoothstep' },
      ];

      const result = getReconnectionEdge('node2', edges);

      expect(result).toEqual({
        id: 'node1-node3',
        source: 'node1',
        target: 'node3',
        type: 'smoothstep',
      });
    });

    it('returns null when node has no incoming edges', () => {
      const edges: Edge[] = [{ id: 'e1', source: 'node1', target: 'node2', type: 'smoothstep' }];

      const result = getReconnectionEdge('node1', edges);

      expect(result).toBeNull();
    });

    it('returns null when node has no outgoing edges', () => {
      const edges: Edge[] = [{ id: 'e1', source: 'node1', target: 'node2', type: 'smoothstep' }];

      const result = getReconnectionEdge('node2', edges);

      expect(result).toBeNull();
    });

    it('returns null when node has multiple incoming edges (branching)', () => {
      const edges: Edge[] = [
        { id: 'e1', source: 'node1', target: 'node3', type: 'smoothstep' },
        { id: 'e2', source: 'node2', target: 'node3', type: 'smoothstep' },
        { id: 'e3', source: 'node3', target: 'node4', type: 'smoothstep' },
      ];

      const result = getReconnectionEdge('node3', edges);

      expect(result).toBeNull();
    });

    it('returns null when node has multiple outgoing edges (branching)', () => {
      const edges: Edge[] = [
        { id: 'e1', source: 'node1', target: 'node2', type: 'smoothstep' },
        { id: 'e2', source: 'node2', target: 'node3', type: 'smoothstep' },
        { id: 'e3', source: 'node2', target: 'node4', type: 'smoothstep' },
      ];

      const result = getReconnectionEdge('node2', edges);

      expect(result).toBeNull();
    });

    it('returns null for disconnected node (no edges)', () => {
      const edges: Edge[] = [
        { id: 'e1', source: 'node1', target: 'node2', type: 'smoothstep' },
        { id: 'e2', source: 'node3', target: 'node4', type: 'smoothstep' },
      ];

      const result = getReconnectionEdge('node5', edges);

      expect(result).toBeNull();
    });

    it('uses smoothstep type for reconnected edges', () => {
      const edges: Edge[] = [
        { id: 'e1', source: 'trigger', target: 'action1', type: 'smoothstep' },
        { id: 'e2', source: 'action1', target: 'action2', type: 'smoothstep' },
      ];

      const result = getReconnectionEdge('action1', edges);

      expect(result?.type).toBe('smoothstep');
    });
  });

  describe('reconnectEdgesAfterDeletion', () => {
    it('removes old edges and adds reconnection edge for linear case', () => {
      const edges: Edge[] = [
        { id: 'e1', source: 'node1', target: 'node2', type: 'smoothstep' },
        { id: 'e2', source: 'node2', target: 'node3', type: 'smoothstep' },
        { id: 'e3', source: 'node3', target: 'node4', type: 'smoothstep' },
      ];

      const result = reconnectEdgesAfterDeletion('node2', edges);

      expect(result).toHaveLength(2);
      expect(result).toContainEqual({
        id: 'node1-node3',
        source: 'node1',
        target: 'node3',
        type: 'smoothstep',
      });
      expect(result).toContainEqual({
        id: 'e3',
        source: 'node3',
        target: 'node4',
        type: 'smoothstep',
      });
    });

    it('only removes edges when reconnection not applicable', () => {
      const edges: Edge[] = [
        { id: 'e1', source: 'node1', target: 'node2', type: 'smoothstep' },
        { id: 'e2', source: 'node2', target: 'node3', type: 'smoothstep' },
        { id: 'e3', source: 'node2', target: 'node4', type: 'smoothstep' },
      ];

      const result = reconnectEdgesAfterDeletion('node2', edges);

      // All edges connected to node2 should be removed (no reconnection because multiple outgoing edges)
      expect(result).toHaveLength(0);
    });

    it('preserves unrelated edges', () => {
      const edges: Edge[] = [
        { id: 'e1', source: 'node1', target: 'node2', type: 'smoothstep' },
        { id: 'e2', source: 'node2', target: 'node3', type: 'smoothstep' },
        { id: 'e3', source: 'node4', target: 'node5', type: 'smoothstep' },
      ];

      const result = reconnectEdgesAfterDeletion('node2', edges);

      expect(result).toHaveLength(2);
      // Should have reconnection edge + unrelated edge
      expect(result).toContainEqual({
        id: 'node1-node3',
        source: 'node1',
        target: 'node3',
        type: 'smoothstep',
      });
      expect(result).toContainEqual({
        id: 'e3',
        source: 'node4',
        target: 'node5',
        type: 'smoothstep',
      });
    });

    it('handles empty edges array', () => {
      const edges: Edge[] = [];

      const result = reconnectEdgesAfterDeletion('node1', edges);

      expect(result).toEqual([]);
    });
  });
});
