import { DesignSystem, Component, DesignToken } from '../design-system/components';
import { KnowledgeGraph } from '../knowledge-graph';

jest.mock('../knowledge-graph');

describe('DesignSystem', () => {
  let designSystem: DesignSystem;
  let mockKnowledgeGraph: jest.Mocked<KnowledgeGraph>;

  beforeEach(() => {
    mockKnowledgeGraph = new KnowledgeGraph() as jest.Mocked<KnowledgeGraph>;
    designSystem = new DesignSystem(mockKnowledgeGraph);
  });

  describe('addComponent', () => {
    it('adds component and updates knowledge graph', async () => {
      const component: Component = {
        id: 'button-primary',
        type: 'atom',
        name: 'Primary Button',
        description: 'Main call-to-action button',
        tokens: [],
        props: { variant: 'primary' },
        variants: ['default', 'large'],
        accessibility: {
          role: 'button',
          ariaProps: { 'aria-pressed': 'false' }
        }
      };

      await designSystem.addComponent(component);

      expect(mockKnowledgeGraph.addNode).toHaveBeenCalledWith({
        id: 'component:button-primary',
        type: 'component',
        data: component
      });
    });
  });

  describe('addToken', () => {
    it('adds token and updates knowledge graph', async () => {
      const token: DesignToken = {
        type: 'color',
        name: 'primary-500',
        value: '#0066CC'
      };

      await designSystem.addToken(token);

      expect(mockKnowledgeGraph.addNode).toHaveBeenCalledWith({
        id: 'token:primary-500',
        type: 'design_token',
        data: token
      });
    });
  });

  describe('getComponent', () => {
    it('retrieves component by id', async () => {
      const component: Component = {
        id: 'card',
        type: 'molecule',
        name: 'Card',
        description: 'Container component',
        tokens: [],
        props: {},
        variants: [],
        accessibility: {
          role: 'article',
          ariaProps: {}
        }
      };

      await designSystem.addComponent(component);
      const retrieved = await designSystem.getComponent('card');
      
      expect(retrieved).toEqual(component);
    });

    it('returns undefined for non-existent component', async () => {
      const component = await designSystem.getComponent('non-existent');
      expect(component).toBeUndefined();
    });
  });

  describe('getComponentsByType', () => {
    it('returns components filtered by type', async () => {
      const atom: Component = {
        id: 'button',
        type: 'atom',
        name: 'Button',
        description: 'Button component',
        tokens: [],
        props: {},
        variants: [],
        accessibility: {
          role: 'button',
          ariaProps: {}
        }
      };

      const molecule: Component = {
        id: 'card',
        type: 'molecule',
        name: 'Card',
        description: 'Card component',
        tokens: [],
        props: {},
        variants: [],
        accessibility: {
          role: 'article',
          ariaProps: {}
        }
      };

      await designSystem.addComponent(atom);
      await designSystem.addComponent(molecule);

      const atoms = await designSystem.getComponentsByType('atom');
      expect(atoms).toHaveLength(1);
      expect(atoms[0].id).toBe('button');
    });
  });

  describe('validateComponent', () => {
    it('validates component with required fields', async () => {
      const token: DesignToken = {
        type: 'color',
        name: 'primary',
        value: '#000'
      };
      await designSystem.addToken(token);

      const component: Component = {
        id: 'button',
        type: 'atom',
        name: 'Button',
        description: 'Button component',
        tokens: [token],
        props: {},
        variants: [],
        accessibility: {
          role: 'button',
          ariaProps: {}
        }
      };

      const isValid = await designSystem.validateComponent(component);
      expect(isValid).toBe(true);
    });

    it('invalidates component with missing fields', async () => {
      const component: Component = {
        id: '',
        type: 'atom',
        name: '',
        description: '',
        tokens: [],
        props: {},
        variants: [],
        accessibility: {
          role: '',
          ariaProps: {}
        }
      };

      const isValid = await designSystem.validateComponent(component);
      expect(isValid).toBe(false);
    });

    it('invalidates component with non-existent tokens', async () => {
      const component: Component = {
        id: 'button',
        type: 'atom',
        name: 'Button',
        description: 'Button component',
        tokens: [{ type: 'color', name: 'non-existent', value: '#000' }],
        props: {},
        variants: [],
        accessibility: {
          role: 'button',
          ariaProps: {}
        }
      };

      const isValid = await designSystem.validateComponent(component);
      expect(isValid).toBe(false);
    });
  });

  describe('generateDocumentation', () => {
    it('generates markdown documentation', async () => {
      const token: DesignToken = {
        type: 'color',
        name: 'primary',
        value: '#000'
      };

      const component: Component = {
        id: 'button',
        type: 'atom',
        name: 'Button',
        description: 'Button component',
        tokens: [token],
        props: { variant: 'primary' },
        variants: [],
        accessibility: {
          role: 'button',
          ariaProps: {}
        }
      };

      await designSystem.addToken(token);
      await designSystem.addComponent(component);

      const docs = await designSystem.generateDocumentation();
      
      expect(docs).toContain('# Design System Documentation');
      expect(docs).toContain('## Design Tokens');
      expect(docs).toContain('### primary');
      expect(docs).toContain('## Atoms');
      expect(docs).toContain('### Button');
      expect(docs).toContain('"variant": "primary"');
    });
  });
}); 