/**
 * GenUI DynamicRenderer 测试
 */
import { describe, it, expect, vi } from 'vitest';
import { render } from '@testing-library/react';
import { DynamicRenderer } from '../DynamicRenderer';
import type { UISchema, RenderContext } from '../types';

// 创建测试上下文
const createTestContext = (overrides?: Partial<RenderContext>): RenderContext => ({
  onAction: vi.fn(),
  theme: 'light',
  loading: false,
  agentType: 'manager',
  ...overrides,
});

// Helper to find text in container
const findText = (container: HTMLElement, text: string): HTMLElement | null => {
  const allElements = container.querySelectorAll('*');
  for (const el of allElements) {
    if (el.textContent?.includes(text)) {
      return el as HTMLElement;
    }
  }
  return null;
};

describe('DynamicRenderer', () => {
  describe('Basic Rendering', () => {
    it('should render null when components array is empty', () => {
      const schema: UISchema = { components: [] };
      const context = createTestContext();
      
      const { container } = render(<DynamicRenderer schema={schema} context={context} />);
      expect(container.firstChild).toBeNull();
    });

    it('should render null when components is undefined', () => {
      const schema: UISchema = { components: undefined as any };
      const context = createTestContext();
      
      const { container } = render(<DynamicRenderer schema={schema} context={context} />);
      expect(container.firstChild).toBeNull();
    });

    it('should render text component correctly', () => {
      const schema: UISchema = {
        components: [
          { type: 'text', props: { content: 'Hello GenUI', variant: 'h2' } }
        ]
      };
      const context = createTestContext();
      
      const { container } = render(<DynamicRenderer schema={schema} context={context} />);
      expect(findText(container, 'Hello GenUI')).not.toBeNull();
    });

    it('should render alert component correctly', () => {
      const schema: UISchema = {
        components: [
          { 
            type: 'alert', 
            props: { 
              type: 'info', 
              title: 'Test Alert', 
              description: 'This is a test' 
            } 
          }
        ]
      };
      const context = createTestContext();
      
      const { container } = render(<DynamicRenderer schema={schema} context={context} />);
      expect(findText(container, 'Test Alert')).not.toBeNull();
      expect(findText(container, 'This is a test')).not.toBeNull();
    });

    it('should render progress bar component correctly', () => {
      const schema: UISchema = {
        components: [
          { 
            type: 'progress_bar', 
            props: { 
              label: 'Progress', 
              value: 75, 
              max: 100,
              showPercentage: true 
            } 
          }
        ]
      };
      const context = createTestContext();
      
      const { container } = render(<DynamicRenderer schema={schema} context={context} />);
      expect(findText(container, 'Progress')).not.toBeNull();
      expect(findText(container, '75%')).not.toBeNull();
    });
  });

  describe('Layout Modes', () => {
    it('should apply vertical layout by default', () => {
      const schema: UISchema = {
        layout: 'vertical',
        components: [
          { type: 'text', props: { content: 'Item 1' } },
          { type: 'text', props: { content: 'Item 2' } }
        ]
      };
      const context = createTestContext();
      
      const { container } = render(<DynamicRenderer schema={schema} context={context} />);
      expect(container.firstChild).toHaveClass('flex-col');
    });

    it('should apply horizontal layout', () => {
      const schema: UISchema = {
        layout: 'horizontal',
        components: [
          { type: 'text', props: { content: 'Item 1' } },
          { type: 'text', props: { content: 'Item 2' } }
        ]
      };
      const context = createTestContext();
      
      const { container } = render(<DynamicRenderer schema={schema} context={context} />);
      expect(container.firstChild).toHaveClass('flex-row');
    });

    it('should apply grid layout', () => {
      const schema: UISchema = {
        layout: 'grid',
        components: [
          { type: 'text', props: { content: 'Item 1' } },
          { type: 'text', props: { content: 'Item 2' } }
        ]
      };
      const context = createTestContext();
      
      const { container } = render(<DynamicRenderer schema={schema} context={context} />);
      expect(container.firstChild).toHaveClass('grid');
    });
  });

  describe('Gap Settings', () => {
    it('should apply small gap', () => {
      const schema: UISchema = {
        gap: 'sm',
        components: [{ type: 'text', props: { content: 'Test' } }]
      };
      const context = createTestContext();
      
      const { container } = render(<DynamicRenderer schema={schema} context={context} />);
      expect(container.firstChild).toHaveClass('gap-2');
    });

    it('should apply medium gap by default', () => {
      const schema: UISchema = {
        components: [{ type: 'text', props: { content: 'Test' } }]
      };
      const context = createTestContext();
      
      const { container } = render(<DynamicRenderer schema={schema} context={context} />);
      expect(container.firstChild).toHaveClass('gap-4');
    });

    it('should apply large gap', () => {
      const schema: UISchema = {
        gap: 'lg',
        components: [{ type: 'text', props: { content: 'Test' } }]
      };
      const context = createTestContext();
      
      const { container } = render(<DynamicRenderer schema={schema} context={context} />);
      expect(container.firstChild).toHaveClass('gap-6');
    });
  });

  describe('Unknown Components', () => {
    it('should render warning for unknown component types', () => {
      const schema: UISchema = {
        components: [
          { type: 'unknown_type' as any, props: {} }
        ]
      };
      const context = createTestContext();
      
      const { container } = render(<DynamicRenderer schema={schema} context={context} />);
      expect(findText(container, '未知组件类型: unknown_type')).not.toBeNull();
    });
  });

  describe('Container Component', () => {
    it('should render nested components in container', () => {
      const schema: UISchema = {
        components: [
          {
            type: 'container',
            props: {
              layout: 'vertical',
              children: [
                { type: 'text', props: { content: 'Nested Item 1' } },
                { type: 'text', props: { content: 'Nested Item 2' } }
              ]
            }
          }
        ]
      };
      const context = createTestContext();
      
      const { container } = render(<DynamicRenderer schema={schema} context={context} />);
      expect(findText(container, 'Nested Item 1')).not.toBeNull();
      expect(findText(container, 'Nested Item 2')).not.toBeNull();
    });

    it('should apply grid layout to container', () => {
      const schema: UISchema = {
        components: [
          {
            type: 'container',
            id: 'grid-container',
            props: {
              layout: 'grid',
              columns: 3,
              children: [
                { type: 'text', props: { content: 'Grid Item' } }
              ]
            }
          }
        ]
      };
      const context = createTestContext();
      
      const { container } = render(<DynamicRenderer schema={schema} context={context} />);
      const gridContainer = container.querySelector('.grid');
      expect(gridContainer).toBeInTheDocument();
    });
  });

  describe('Component IDs', () => {
    it('should use provided component ID as key', () => {
      const schema: UISchema = {
        components: [
          { id: 'custom-id', type: 'text', props: { content: 'With ID' } }
        ]
      };
      const context = createTestContext();
      
      const { container } = render(<DynamicRenderer schema={schema} context={context} />);
      expect(findText(container, 'With ID')).not.toBeNull();
    });
  });

  describe('Multiple Components', () => {
    it('should render multiple different component types', () => {
      const schema: UISchema = {
        components: [
          { type: 'text', props: { content: 'Title', variant: 'h1' } },
          { type: 'alert', props: { type: 'warning', title: 'Warning!' } },
          { type: 'progress_bar', props: { label: 'Loading', value: 50, max: 100 } }
        ]
      };
      const context = createTestContext();
      
      const { container } = render(<DynamicRenderer schema={schema} context={context} />);
      expect(findText(container, 'Title')).not.toBeNull();
      expect(findText(container, 'Warning!')).not.toBeNull();
      expect(findText(container, 'Loading')).not.toBeNull();
    });
  });

  describe('Custom ClassName', () => {
    it('should apply custom className', () => {
      const schema: UISchema = {
        components: [{ type: 'text', props: { content: 'Test' } }]
      };
      const context = createTestContext();
      
      const { container } = render(
        <DynamicRenderer schema={schema} context={context} className="custom-class" />
      );
      expect(container.firstChild).toHaveClass('custom-class');
    });
  });
});
