/**
 * Tests for Event Handlers Generator
 */

import * as path from 'path';
import { generateEventHandlers } from './event-handlers-generator';
import { GeneratorContext } from '../types';
import { ExtendedWorkflow as _ExtendedWorkflow } from '../../parser/extended-workflow-schema';
import { Workflow } from '../../types/workflow';

describe('Event Handlers Generator', () => {
  let baseWorkflow: Workflow;
  let baseContext: GeneratorContext;
  const testOutputDir = '/tmp/test-output';

  beforeEach(() => {
    baseWorkflow = {
      workflow: {
        id: 'test-app',
        version: '1.0.0',
        name: 'Test Application',
        description: 'Test workflow',
      },
      models: {},
      stack: {},
    };

    baseContext = {
      workflow: baseWorkflow,
      extendedWorkflow: undefined,
      outputDirectory: testOutputDir,
      executionPlan: { workflow: baseWorkflow, componentPlans: new Map() },
    };
  });

  describe('Configuration Detection', () => {
    it('should skip generation when no extended workflow', async () => {
      const result = await generateEventHandlers(baseContext);
      expect(result.files).toHaveLength(0);
    });

    it('should skip generation when no events defined', async () => {
      const extendedWorkflow = {
        ...baseWorkflow.workflow as any,
        technology: {
          backend: { framework: 'express', language: 'typescript' },
          cache: { provider: 'redis', use: 'local' },
        },
      };

      const result = await generateEventHandlers({ ...baseContext, extendedWorkflow });
      expect(result.files).toHaveLength(0);
    });

    it('should skip generation when no Redis cache', async () => {
      const extendedWorkflow = {
        ...baseWorkflow.workflow as any,
        technology: {
          backend: { framework: 'express', language: 'typescript' },
        },
        events: {
          user_created: {
            description: 'User created',
            payload: { user_id: 'string' },
          },
        },
      };

      const result = await generateEventHandlers({ ...baseContext, extendedWorkflow });
      expect(result.files).toHaveLength(0);
    });

    it('should generate handlers when events and Redis are configured', async () => {
      const extendedWorkflow = {
        ...baseWorkflow.workflow as any,
        technology: {
          backend: { framework: 'express', language: 'typescript' },
          cache: { provider: 'redis', use: 'local' },
        },
        events: {
          user_created: {
            description: 'User created',
            payload: { user_id: 'string' },
          },
        },
      };

      const result = await generateEventHandlers({ ...baseContext, extendedWorkflow });
      expect(result.files.length).toBeGreaterThan(0);
    });
  });

  describe('File Generation', () => {
    it('should generate handler file for each event', async () => {
      const extendedWorkflow = {
        ...baseWorkflow.workflow as any,
        technology: {
          backend: { framework: 'express', language: 'typescript' },
          cache: { provider: 'redis', use: 'local' },
        },
        events: {
          user_created: {
            description: 'User created',
            payload: { user_id: 'string' },
          },
          task_assigned: {
            description: 'Task assigned',
            payload: { task_id: 'string' },
          },
        },
      };

      const result = await generateEventHandlers({ ...baseContext, extendedWorkflow });

      const handlerFiles = result.files.filter(f => f.path.includes('/handlers/') && !f.path.includes('index'));
      expect(handlerFiles).toHaveLength(2);

      // Verify all paths are absolute
      handlerFiles.forEach(f => expect(path.isAbsolute(f.path)).toBe(true));

      expect(handlerFiles.map(f => f.path)).toContain(path.join(testOutputDir, 'backend', 'src', 'events', 'handlers', 'user_created-handler.ts'));
      expect(handlerFiles.map(f => f.path)).toContain(path.join(testOutputDir, 'backend', 'src', 'events', 'handlers', 'task_assigned-handler.ts'));
    });

    it('should generate index file', async () => {
      const extendedWorkflow = {
        ...baseWorkflow.workflow as any,
        technology: {
          backend: { framework: 'express', language: 'typescript' },
          cache: { provider: 'redis', use: 'local' },
        },
        events: {
          user_created: {
            description: 'User created',
            payload: { user_id: 'string' },
          },
        },
      };

      const result = await generateEventHandlers({ ...baseContext, extendedWorkflow });
      const indexFile = result.files.find(f => f.path.includes('/handlers/index.ts'));

      expect(indexFile).toBeDefined();
      expect(indexFile!.content).toContain('export { handleUserCreatedHandler }');
    });

    it('should generate subscriber initializer', async () => {
      const extendedWorkflow = {
        ...baseWorkflow.workflow as any,
        technology: {
          backend: { framework: 'express', language: 'typescript' },
          cache: { provider: 'redis', use: 'local' },
        },
        events: {
          user_created: {
            description: 'User created',
            payload: { user_id: 'string' },
          },
        },
      };

      const result = await generateEventHandlers({ ...baseContext, extendedWorkflow });
      const initFile = result.files.find(f => f.path.includes('subscriber-initializer.ts'));

      expect(initFile).toBeDefined();
      expect(initFile!.content).toContain('export async function initializeAllSubscribers');
      expect(initFile!.content).toContain('getSubscriberConfigs');
    });
  });

  describe('Handler Implementation', () => {
    it('should include TODO comment for implementation', async () => {
      const extendedWorkflow = {
        ...baseWorkflow.workflow as any,
        technology: {
          backend: { framework: 'express', language: 'typescript' },
          cache: { provider: 'redis', use: 'local' },
        },
        events: {
          user_created: {
            description: 'User created',
            payload: { user_id: 'string' },
          },
        },
      };

      const result = await generateEventHandlers({ ...baseContext, extendedWorkflow });
      const handlerFile = result.files.find(f => f.path.includes('user_created-handler.ts'));

      expect(handlerFile!.content).toContain('TODO: Implement your business logic here');
    });

    it('should include error handling', async () => {
      const extendedWorkflow = {
        ...baseWorkflow.workflow as any,
        technology: {
          backend: { framework: 'express', language: 'typescript' },
          cache: { provider: 'redis', use: 'local' },
        },
        events: {
          user_created: {
            description: 'User created',
            payload: { user_id: 'string' },
          },
        },
      };

      const result = await generateEventHandlers({ ...baseContext, extendedWorkflow });
      const handlerFile = result.files.find(f => f.path.includes('user_created-handler.ts'));

      expect(handlerFile!.content).toContain('try {');
      expect(handlerFile!.content).toContain('catch (error)');
      expect(handlerFile!.content).toContain('throw error');
    });

    it('should import correct event type', async () => {
      const extendedWorkflow = {
        ...baseWorkflow.workflow as any,
        technology: {
          backend: { framework: 'express', language: 'typescript' },
          cache: { provider: 'redis', use: 'local' },
        },
        events: {
          task_completed: {
            description: 'Task completed',
            payload: { task_id: 'string' },
          },
        },
      };

      const result = await generateEventHandlers({ ...baseContext, extendedWorkflow });
      const handlerFile = result.files.find(f => f.path.includes('task_completed-handler.ts'));

      expect(handlerFile!.content).toContain("import { TaskCompletedEvent } from '../types/events'");
    });
  });

  describe('Subscriber Configuration', () => {
    it('should wire up all handlers in initializer', async () => {
      const extendedWorkflow = {
        ...baseWorkflow.workflow as any,
        technology: {
          backend: { framework: 'express', language: 'typescript' },
          cache: { provider: 'redis', use: 'local' },
        },
        events: {
          user_created: {
            description: 'User created',
            payload: { user_id: 'string' },
          },
          user_updated: {
            description: 'User updated',
            payload: { user_id: 'string' },
          },
        },
      };

      const result = await generateEventHandlers({ ...baseContext, extendedWorkflow });
      const initFile = result.files.find(f => f.path.includes('subscriber-initializer.ts'));

      expect(initFile!.content).toContain("eventType: 'user_created'");
      expect(initFile!.content).toContain("eventType: 'user_updated'");
      expect(initFile!.content).toContain('handleUserCreatedHandler');
      expect(initFile!.content).toContain('handleUserUpdatedHandler');
    });
  });

  describe('Code Quality', () => {
    it('should include DO NOT EDIT warnings', async () => {
      const extendedWorkflow = {
        ...baseWorkflow.workflow as any,
        technology: {
          backend: { framework: 'express', language: 'typescript' },
          cache: { provider: 'redis', use: 'local' },
        },
        events: {
          user_created: {
            description: 'User created',
            payload: { user_id: 'string' },
          },
        },
      };

      const result = await generateEventHandlers({ ...baseContext, extendedWorkflow });

      for (const file of result.files) {
        expect(file.content).toContain('DO NOT EDIT MANUALLY');
      }
    });
  });
});
