"use strict";
/**
 * Tests for Lazy Generator Registry
 */
Object.defineProperty(exports, "__esModule", { value: true });
const lazy_registry_1 = require("./lazy-registry");
const generator_registry_1 = require("./generator-registry");
describe('LazyGeneratorRegistry', () => {
    let baseRegistry;
    let lazyRegistry;
    beforeEach(() => {
        baseRegistry = new generator_registry_1.GeneratorRegistry();
        lazyRegistry = new lazy_registry_1.LazyGeneratorRegistry(baseRegistry);
    });
    describe('registerLazy()', () => {
        it('should register a generator without loading it', () => {
            const factory = jest.fn(() => ({
                id: 'test-gen',
                name: 'Test Generator',
                description: 'Test',
                generate: jest.fn(),
            }));
            lazyRegistry.registerLazy('test-gen', 'custom', factory);
            // Factory should not be called yet
            expect(factory).not.toHaveBeenCalled();
            expect(lazyRegistry.isLoaded('test-gen')).toBe(false);
        });
        it('should track registered generators', () => {
            lazyRegistry.registerLazy('gen1', 'custom', () => ({
                id: 'gen1',
                name: 'Gen 1',
                description: 'Test',
                generate: jest.fn(),
            }));
            lazyRegistry.registerLazy('gen2', 'custom', () => ({
                id: 'gen2',
                name: 'Gen 2',
                description: 'Test',
                generate: jest.fn(),
            }));
            expect(lazyRegistry.listGeneratorIds()).toEqual(['gen1', 'gen2']);
            expect(lazyRegistry.listLoadedGeneratorIds()).toEqual([]);
            expect(lazyRegistry.listPendingGeneratorIds()).toEqual(['gen1', 'gen2']);
        });
    });
    describe('getGenerator()', () => {
        it('should load generator on first access', async () => {
            const factory = jest.fn(() => ({
                id: 'test-gen',
                name: 'Test Generator',
                description: 'Test',
                generate: jest.fn(),
            }));
            lazyRegistry.registerLazy('test-gen', 'custom', factory);
            // Get generator - should trigger load
            const generator = await lazyRegistry.getGenerator('test-gen');
            expect(factory).toHaveBeenCalledTimes(1);
            expect(generator).toBeDefined();
            expect(generator?.id).toBe('test-gen');
            expect(lazyRegistry.isLoaded('test-gen')).toBe(true);
        });
        it('should not reload generator on subsequent access', async () => {
            const factory = jest.fn(() => ({
                id: 'test-gen',
                name: 'Test Generator',
                description: 'Test',
                generate: jest.fn(),
            }));
            lazyRegistry.registerLazy('test-gen', 'custom', factory);
            // Get generator twice
            await lazyRegistry.getGenerator('test-gen');
            await lazyRegistry.getGenerator('test-gen');
            // Factory should only be called once
            expect(factory).toHaveBeenCalledTimes(1);
        });
        it('should return undefined for unregistered generator', async () => {
            const generator = await lazyRegistry.getGenerator('nonexistent');
            expect(generator).toBeUndefined();
        });
        it('should support async factory functions', async () => {
            const factory = jest.fn(async () => {
                await new Promise(resolve => setTimeout(resolve, 10));
                return {
                    id: 'async-gen',
                    name: 'Async Generator',
                    description: 'Test',
                    generate: jest.fn(),
                };
            });
            lazyRegistry.registerLazy('async-gen', 'custom', factory);
            const generator = await lazyRegistry.getGenerator('async-gen');
            expect(generator).toBeDefined();
            expect(generator?.id).toBe('async-gen');
        });
    });
    describe('getFrontendGenerator()', () => {
        it('should load and return frontend generator', async () => {
            lazyRegistry.registerLazy('react', 'frontend', () => ({
                id: 'react',
                name: 'React',
                description: 'React generator',
                framework: 'react',
                generate: jest.fn(),
            }));
            const generator = await lazyRegistry.getFrontendGenerator('react');
            expect(generator).toBeDefined();
            expect(generator.framework).toBe('react');
        });
        it('should match by framework property', async () => {
            lazyRegistry.registerLazy('vue', 'frontend', () => ({
                id: 'vue-gen',
                name: 'Vue',
                description: 'Vue generator',
                framework: 'vue',
                generate: jest.fn(),
            }));
            // Should match by framework property even if ID is different
            const generator = await lazyRegistry.getFrontendGenerator('vue');
            expect(generator).toBeDefined();
            expect(generator.framework).toBe('vue');
        });
    });
    describe('getBackendGenerator()', () => {
        it('should load and return backend generator', async () => {
            lazyRegistry.registerLazy('typescript-express', 'backend', () => ({
                id: 'typescript-express',
                name: 'TypeScript Express',
                description: 'Express generator',
                language: 'typescript',
                framework: 'express',
                generate: jest.fn(),
            }));
            const generator = await lazyRegistry.getBackendGenerator('typescript', 'express');
            expect(generator).toBeDefined();
            expect(generator.language).toBe('typescript');
            expect(generator.framework).toBe('express');
        });
        it('should match by language only if framework not specified', async () => {
            lazyRegistry.registerLazy('python-flask', 'backend', () => ({
                id: 'python-flask',
                name: 'Python Flask',
                description: 'Flask generator',
                language: 'python',
                framework: 'flask',
                generate: jest.fn(),
            }));
            const generator = await lazyRegistry.getBackendGenerator('python');
            expect(generator).toBeDefined();
            expect(generator.language).toBe('python');
        });
        it('should return undefined if language is not provided', async () => {
            const generator = await lazyRegistry.getBackendGenerator();
            expect(generator).toBeUndefined();
        });
    });
    describe('getDatabaseGenerator()', () => {
        it('should load and return database generator', async () => {
            lazyRegistry.registerLazy('prisma', 'database', () => ({
                id: 'prisma',
                name: 'Prisma',
                description: 'Prisma generator',
                database: 'prisma',
                generate: jest.fn(),
            }));
            const generator = await lazyRegistry.getDatabaseGenerator('prisma');
            expect(generator).toBeDefined();
            expect(generator?.id).toBe('prisma');
        });
    });
    describe('getTestGenerator()', () => {
        it('should load and return test generator', async () => {
            lazyRegistry.registerLazy('vitest', 'test', () => ({
                id: 'vitest',
                name: 'Vitest',
                description: 'Vitest generator',
                testFramework: 'vitest',
                generate: jest.fn(),
            }));
            const generator = await lazyRegistry.getTestGenerator('vitest');
            expect(generator).toBeDefined();
            expect(generator?.id).toBe('vitest');
        });
    });
    describe('getCustomGenerators()', () => {
        it('should load all custom generators', async () => {
            lazyRegistry.registerLazy('gen1', 'custom', () => ({
                id: 'gen1',
                name: 'Generator 1',
                description: 'Test',
                generate: jest.fn(),
            }));
            lazyRegistry.registerLazy('gen2', 'custom', () => ({
                id: 'gen2',
                name: 'Generator 2',
                description: 'Test',
                generate: jest.fn(),
            }));
            const generators = await lazyRegistry.getCustomGenerators();
            expect(generators).toHaveLength(2);
            expect(generators[0].id).toBe('gen1');
            expect(generators[1].id).toBe('gen2');
        });
        it('should include custom generators from base registry', async () => {
            // Add custom generator to base registry
            baseRegistry.registerCustomGenerator({
                id: 'base-gen',
                name: 'Base Generator',
                description: 'Test',
                generate: jest.fn(),
            });
            // Add lazy custom generator
            lazyRegistry.registerLazy('lazy-gen', 'custom', () => ({
                id: 'lazy-gen',
                name: 'Lazy Generator',
                description: 'Test',
                generate: jest.fn(),
            }));
            const generators = await lazyRegistry.getCustomGenerators();
            expect(generators).toHaveLength(2);
            expect(generators.map(g => g.id).sort()).toEqual(['base-gen', 'lazy-gen']);
        });
    });
    describe('preload()', () => {
        it('should load specific generators', async () => {
            const factory1 = jest.fn(() => ({
                id: 'gen1',
                name: 'Gen 1',
                description: 'Test',
                generate: jest.fn(),
            }));
            const factory2 = jest.fn(() => ({
                id: 'gen2',
                name: 'Gen 2',
                description: 'Test',
                generate: jest.fn(),
            }));
            const factory3 = jest.fn(() => ({
                id: 'gen3',
                name: 'Gen 3',
                description: 'Test',
                generate: jest.fn(),
            }));
            lazyRegistry.registerLazy('gen1', 'custom', factory1);
            lazyRegistry.registerLazy('gen2', 'custom', factory2);
            lazyRegistry.registerLazy('gen3', 'custom', factory3);
            // Preload only gen1 and gen2
            await lazyRegistry.preload(['gen1', 'gen2']);
            expect(factory1).toHaveBeenCalledTimes(1);
            expect(factory2).toHaveBeenCalledTimes(1);
            expect(factory3).not.toHaveBeenCalled();
            expect(lazyRegistry.listLoadedGeneratorIds()).toEqual(['gen1', 'gen2']);
            expect(lazyRegistry.listPendingGeneratorIds()).toEqual(['gen3']);
        });
        it('should load generators in parallel', async () => {
            const startTimes = [];
            const endTimes = [];
            for (let i = 0; i < 3; i++) {
                lazyRegistry.registerLazy(`gen${i}`, 'custom', async () => {
                    startTimes.push(Date.now());
                    await new Promise(resolve => setTimeout(resolve, 50));
                    endTimes.push(Date.now());
                    return {
                        id: `gen${i}`,
                        name: `Gen ${i}`,
                        description: 'Test',
                        generate: jest.fn(),
                    };
                });
            }
            const start = Date.now();
            await lazyRegistry.preload(['gen0', 'gen1', 'gen2']);
            const duration = Date.now() - start;
            // Should complete in ~50ms (parallel) not ~150ms (sequential)
            expect(duration).toBeLessThan(120);
        });
    });
    describe('preloadAll()', () => {
        it('should load all registered generators', async () => {
            const factory1 = jest.fn(() => ({
                id: 'gen1',
                name: 'Gen 1',
                description: 'Test',
                generate: jest.fn(),
            }));
            const factory2 = jest.fn(() => ({
                id: 'gen2',
                name: 'Gen 2',
                description: 'Test',
                generate: jest.fn(),
            }));
            lazyRegistry.registerLazy('gen1', 'custom', factory1);
            lazyRegistry.registerLazy('gen2', 'custom', factory2);
            await lazyRegistry.preloadAll();
            expect(factory1).toHaveBeenCalledTimes(1);
            expect(factory2).toHaveBeenCalledTimes(1);
            expect(lazyRegistry.listLoadedGeneratorIds()).toEqual(['gen1', 'gen2']);
            expect(lazyRegistry.listPendingGeneratorIds()).toEqual([]);
        });
    });
    describe('getLoadStats()', () => {
        it('should return loading statistics', async () => {
            lazyRegistry.registerLazy('gen1', 'custom', async () => {
                // Add a small delay to ensure measurable load time
                await new Promise(resolve => setTimeout(resolve, 1));
                return {
                    id: 'gen1',
                    name: 'Gen 1',
                    description: 'Test',
                    generate: jest.fn(),
                };
            });
            lazyRegistry.registerLazy('gen2', 'custom', () => ({
                id: 'gen2',
                name: 'Gen 2',
                description: 'Test',
                generate: jest.fn(),
            }));
            // Load one generator
            await lazyRegistry.getGenerator('gen1');
            const stats = lazyRegistry.getLoadStats();
            expect(stats.total).toBe(2);
            expect(stats.loaded).toBe(1);
            expect(stats.pending).toBe(1);
            expect(stats.totalLoadTime).toBeGreaterThanOrEqual(0); // Changed to >= since it may be 0-1ms
            expect(stats.averageLoadTime).toBeGreaterThanOrEqual(0);
            expect(stats.loadTimes.get('gen1')).toBeGreaterThanOrEqual(0);
        });
        it('should return zero stats for empty registry', () => {
            const stats = lazyRegistry.getLoadStats();
            expect(stats.total).toBe(0);
            expect(stats.loaded).toBe(0);
            expect(stats.pending).toBe(0);
            expect(stats.totalLoadTime).toBe(0);
            expect(stats.averageLoadTime).toBe(0);
        });
    });
    describe('error handling', () => {
        it('should handle generator factory errors gracefully', async () => {
            const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
            lazyRegistry.registerLazy('failing-gen', 'custom', () => {
                throw new Error('Factory failed');
            });
            const generator = await lazyRegistry.getGenerator('failing-gen');
            expect(generator).toBeUndefined();
            expect(consoleSpy).toHaveBeenCalledWith('Failed to load generator "failing-gen":', expect.any(Error));
            // Should mark as loaded to prevent retry loops
            expect(lazyRegistry.isLoaded('failing-gen')).toBe(true);
            consoleSpy.mockRestore();
        });
        it('should handle async factory errors', async () => {
            const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
            lazyRegistry.registerLazy('async-failing-gen', 'custom', async () => {
                await new Promise(resolve => setTimeout(resolve, 10));
                throw new Error('Async factory failed');
            });
            const generator = await lazyRegistry.getGenerator('async-failing-gen');
            expect(generator).toBeUndefined();
            expect(consoleSpy).toHaveBeenCalled();
            consoleSpy.mockRestore();
        });
    });
    describe('getBaseRegistry()', () => {
        it('should return underlying base registry', () => {
            const registry = lazyRegistry.getBaseRegistry();
            expect(registry).toBe(baseRegistry);
        });
    });
});
describe('createLazyRegistry()', () => {
    let baseRegistry;
    beforeEach(() => {
        baseRegistry = new generator_registry_1.GeneratorRegistry();
    });
    it('should create lazy registry with all standard generators', () => {
        const lazyRegistry = (0, lazy_registry_1.createLazyRegistry)(baseRegistry);
        const ids = lazyRegistry.listGeneratorIds();
        expect(ids).toContain('react');
        expect(ids).toContain('typescript-express');
        expect(ids).toContain('typescript-cli');
        expect(ids).toContain('prisma');
        expect(ids).toContain('drizzle');
        expect(ids).toContain('vitest');
        expect(ids).toContain('jest');
        expect(ids).toContain('playwright');
        expect(ids).toContain('cli-jest');
        expect(ids).toContain('markdown');
        expect(ids).toContain('github-actions');
        expect(ids).toContain('environment');
        expect(ids).toContain('service');
        expect(ids).toContain('upstash-redis');
    });
    it('should not load generators until accessed', () => {
        const lazyRegistry = (0, lazy_registry_1.createLazyRegistry)(baseRegistry);
        const loaded = lazyRegistry.listLoadedGeneratorIds();
        const pending = lazyRegistry.listPendingGeneratorIds();
        expect(loaded).toHaveLength(0);
        expect(pending.length).toBeGreaterThan(0);
    });
    it('should load React generator on demand', async () => {
        const lazyRegistry = (0, lazy_registry_1.createLazyRegistry)(baseRegistry);
        const generator = await lazyRegistry.getFrontendGenerator('react');
        expect(generator).toBeDefined();
        expect(generator?.id).toBe('react-frontend'); // Actual React generator ID
        expect(lazyRegistry.isLoaded('react')).toBe(true);
    });
    it('should load Express generator on demand', async () => {
        const lazyRegistry = (0, lazy_registry_1.createLazyRegistry)(baseRegistry);
        const generator = await lazyRegistry.getBackendGenerator('typescript', 'express');
        expect(generator).toBeDefined();
        expect(generator?.id).toBe('typescript-express-backend'); // Actual Express generator ID
        expect(lazyRegistry.isLoaded('typescript-express')).toBe(true);
    });
    it('should load database generators on demand', async () => {
        const lazyRegistry = (0, lazy_registry_1.createLazyRegistry)(baseRegistry);
        const prisma = await lazyRegistry.getDatabaseGenerator('prisma');
        const drizzle = await lazyRegistry.getDatabaseGenerator('drizzle');
        expect(prisma).toBeDefined();
        expect(drizzle).toBeDefined();
        expect(lazyRegistry.isLoaded('prisma')).toBe(true);
        expect(lazyRegistry.isLoaded('drizzle')).toBe(true);
    });
});
//# sourceMappingURL=lazy-registry.test.js.map