/**
 * @fileoverview Tests for the Code Splitter
 */

import { describe, expect, it } from 'vitest';
import { CodeSplitter } from './code-splitter.js';
import { OrdoJSLexer } from './lexer.js';
import { OrdoJSParser } from './parser.js';

describe('CodeSplitter', () => {
  it('should create chunks based on routes', () => {
    // Create test components
    const homeComponent = createTestComponent('Home');
    const aboutComponent = createTestComponent('About');
    const userComponent = createTestComponent('User');
    const settingsComponent = createTestComponent('Settings');

    // Create code splitter
    const splitter = new CodeSplitter({
      routeBasedSplitting: true,
      componentBasedSplitting: false
    });

    // Register components
    splitter.registerComponents([
      homeComponent,
      aboutComponent,
      userComponent,
      settingsComponent
    ]);

    // Register routes
    splitter.registerRoutes([
      {
        path: '/',
        filePath: '/src/routes/index.ordo',
        componentName: 'Home',
        ast: homeComponent,
        params: [],
        isDynamic: false,
        isCatchAll: false,
        priority: 1
      },
      {
        path: '/about',
        filePath: '/src/routes/about.ordo',
        componentName: 'About',
        ast: aboutComponent,
        params: [],
        isDynamic: false,
        isCatchAll: false,
        priority: 1
      },
      {
        path: '/users/:id',
        filePath: '/src/routes/users/[id].ordo',
        componentName: 'User',
        ast: userComponent,
        params: ['id'],
        isDynamic: true,
        isCatchAll: false,
        priority: 2
      },
      {
        path: '/settings',
        filePath: '/src/routes/settings.ordo',
        componentName: 'Settings',
        ast: settingsComponent,
        params: [],
        isDynamic: false,
        isCatchAll: false,
        priority: 1
      }
    ]);

    // Analyze for code splitting
    const result = splitter.analyze();

    // Check that chunks were created
    expect(result.chunks.length).toBeGreaterThan(0);

    // Check that we have a main chunk
    const mainChunk = result.chunks.find(chunk => chunk.isMain);
    expect(mainChunk).toBeDefined();

    // Check that we have a users chunk
    const usersChunk = result.chunks.find(chunk => chunk.name.includes('users'));
    expect(usersChunk).toBeDefined();

    // Check that import map was generated
    expect(Object.keys(result.importMap).length).toBeGreaterThan(0);

    // Check that lazy loading code was generated
    expect(result.lazyLoadingCode).toContain('lazyLoad');
    expect(result.lazyLoadingCode).toContain('preload');
  });

  it('should create component-based chunks', () => {
    // Create test components with dependencies
    const appComponent = createTestComponent('App', ['Header', 'Footer']);
    const headerComponent = createTestComponent('Header');
    const footerComponent = createTestComponent('Footer');
    const sidebarComponent = createTestComponent('Sidebar');
    const buttonComponent = createTestComponent('Button');

    // Create code splitter
    const splitter = new CodeSplitter({
      routeBasedSplitting: false,
      componentBasedSplitting: true
    });

    // Register components
    splitter.registerComponents([
      appComponent,
      headerComponent,
      footerComponent,
      sidebarComponent,
      buttonComponent
    ]);

    // Analyze for code splitting
    const result = splitter.analyze();

    // Check that chunks were created
    expect(result.chunks.length).toBeGreaterThan(0);

    // Check that import map was generated
    expect(Object.keys(result.importMap).length).toBeGreaterThan(0);
  });

  it('should optimize chunks by merging small chunks', () => {
    // Create many small components
    const components = [];
    for (let i = 1; i <= 10; i++) {
      components.push(createTestComponent(`Component${i}`));
    }

    // Create code splitter with low threshold to force merging
    const splitter = new CodeSplitter({
      chunkSizeThreshold: 1000000, // Very high threshold to force merging
      maxChunks: 3
    });

    // Register components
    splitter.registerComponents(components);

    // Register routes (one per component)
    const routes = components.map((component, i) => ({
      path: i === 0 ? '/' : `/route${i}`,
      filePath: `/src/routes/${i === 0 ? 'index' : `route${i}`}.ordo`,
      componentName: `Component${i + 1}`,
      ast: component,
      params: [],
      isDynamic: false,
      isCatchAll: false,
      priority: 1
    }));

    splitter.registerRoutes(routes);

    // Analyze for code splitting
    const result = splitter.analyze();

    // Check that chunks were merged
    expect(result.chunks.length).toBeLessThanOrEqual(3);
  });
});

/**
 * Helper to create a test component
 */
function createTestComponent(name: string, dependencies: string[] = []): any {
  const source = `
    component ${name} {
      client {
        let count = 0;

        function increment() {
          count++;
        }
      }

      markup {
        <div>
          <h1>${name} Component</h1>
          <p>Count: {count}</p>
          <button onclick={increment()}>Increment</button>
        </div>
      }
    }
  `;

  const lexer = new OrdoJSLexer();
  const tokens = lexer.tokenize(source);
  const parser = new OrdoJSParser(tokens);
  const ast = parser.parse();

  // Add dependencies to AST
  ast.dependencies = dependencies;

  return ast;
}
