import { describe, expect, it } from 'vitest';
import { createConnectionRenderer } from './CreateConnectionRenderer';

interface TestConnection {
  nodes: { id: string; name: string }[];
}

interface StringConnection {
  nodes: string[];
}

describe('createConnectionRenderer', () => {
  describe('basic functionality', () => {
    it('should return comma-separated string using selector', () => {
      const connection: TestConnection = {
        nodes: [
          { id: '1', name: 'Item 1' },
          { id: '2', name: 'Item 2' },
          { id: '3', name: 'Item 3' },
        ],
      };

      const selector = (item: { id: string; name: string }) => item.name;
      const renderer = createConnectionRenderer<TestConnection>(
        selector,
        false,
      );
      const result = renderer(connection);

      expect(result).toBe('Item 1, Item 2, Item 3');
    });

    it('should work with simple string arrays', () => {
      const connection: StringConnection = {
        nodes: ['apple', 'banana', 'cherry'],
      };

      const selector = (item: string) => item;
      const renderer = createConnectionRenderer<StringConnection>(
        selector,
        false,
      );
      const result = renderer(connection);

      expect(result).toBe('apple, banana, cherry');
    });

    it('should work with complex selector functions', () => {
      const connection: TestConnection = {
        nodes: [
          { id: '1', name: 'Item 1' },
          { id: '2', name: 'Item 2' },
        ],
      };

      const selector = (item: { id: string; name: string }, index: number) =>
        `${index + 1}. ${item.name} (${item.id})`;
      const renderer = createConnectionRenderer<TestConnection>(
        selector,
        false,
      );
      const result = renderer(connection);

      expect(result).toBe('1. Item 1 (1), 2. Item 2 (2)');
    });

    it('should return empty string when nodes array is empty', () => {
      const connection: TestConnection = { nodes: [] };
      const selector = (item: { id: string; name: string }) => item.name;
      const renderer = createConnectionRenderer<TestConnection>(
        selector,
        false,
      );
      const result = renderer(connection);

      expect(result).toBe('');
    });

    it('should handle selector returning different types', () => {
      interface NumberConnection {
        nodes: { id: number; value: number }[];
      }
      const connection: NumberConnection = {
        nodes: [
          { id: 1, value: 100 },
          { id: 2, value: 200 },
        ],
      };

      const selector = (item: { id: number; value: number }) => item.value;
      const renderer = createConnectionRenderer<NumberConnection>(
        selector,
        false,
      );
      const result = renderer(connection);

      expect(result).toBe('100, 200');
    });

    it('should throw error when connection.nodes is undefined', () => {
      const connection = { nodes: undefined } as unknown as TestConnection;
      const selector = (item: { id: string; name: string }) => item.name;
      const renderer = createConnectionRenderer<TestConnection>(
        selector,
        false,
      );

      expect(() => renderer(connection)).toThrow();
    });

    it('should throw error when value is null', () => {
      const selector = (item: { id: string; name: string }) => item.name;
      const renderer = createConnectionRenderer<TestConnection>(
        selector,
        false,
      );

      expect(() => renderer(null)).toThrow();
    });

    it('should throw error when value is undefined', () => {
      const selector = (item: { id: string; name: string }) => item.name;
      const renderer = createConnectionRenderer<TestConnection>(
        selector,
        false,
      );

      expect(() => renderer(undefined)).toThrow();
    });
  });

  describe('edge cases', () => {
    it('should handle nodes with special characters in comma-separated output', () => {
      const connection: StringConnection = {
        nodes: ['item, with comma', 'item with "quotes"', 'normal item'],
      };

      const selector = (item: string) => item;
      const renderer = createConnectionRenderer<StringConnection>(
        selector,
        false,
      );
      const result = renderer(connection);

      expect(result).toBe('item, with comma, item with "quotes", normal item');
    });

    it('should handle selector returning empty strings', () => {
      const connection: TestConnection = {
        nodes: [
          { id: '1', name: '' },
          { id: '2', name: 'Item 2' },
          { id: '3', name: '' },
        ],
      };

      const selector = (item: { id: string; name: string }) => item.name;
      const renderer = createConnectionRenderer<TestConnection>(
        selector,
        false,
      );
      const result = renderer(connection);

      expect(result).toBe(', Item 2, ');
    });

    it('should handle single node connection', () => {
      const connection: TestConnection = {
        nodes: [{ id: '1', name: 'Single Item' }],
      };

      const selector = (item: { id: string; name: string }) => item.name;
      const renderer = createConnectionRenderer<TestConnection>(
        selector,
        false,
      );
      const result = renderer(connection);

      expect(result).toBe('Single Item');
    });
  });

  describe('type safety', () => {
    it('should work with different connection node types', () => {
      interface CustomConnection {
        nodes: { customField: number; label: string }[];
      }

      const connection: CustomConnection = {
        nodes: [
          { customField: 42, label: 'Custom 1' },
          { customField: 84, label: 'Custom 2' },
        ],
      };

      const selector = (item: { customField: number; label: string }) =>
        `${item.label}: ${item.customField}`;
      const renderer = createConnectionRenderer<CustomConnection>(
        selector,
        false,
      );
      const result = renderer(connection);

      expect(result).toBe('Custom 1: 42, Custom 2: 84');
    });
  });
});
