/**
 * Tests for WebSocket Server Generator
 */

import * as path from 'path';
import { generateWebSocketServer } from './websocket-server-generator';
import { GeneratorContext } from '../types';
import { ExtendedWorkflow as _ExtendedWorkflow } from '../../parser/extended-workflow-schema';
import { Workflow } from '../../types/workflow';

describe('WebSocket Server 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 generateWebSocketServer(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 generateWebSocketServer({ ...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 generateWebSocketServer({ ...baseContext, extendedWorkflow });
      expect(result.files).toHaveLength(0);
    });

    it('should generate WebSocket server 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 generateWebSocketServer({ ...baseContext, extendedWorkflow });
      expect(result.files.length).toBeGreaterThan(0);
    });
  });

  describe('File Generation', () => {
    it('should generate server.ts 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 generateWebSocketServer({ ...baseContext, extendedWorkflow });
      const serverFile = result.files.find(f => f.path.includes('/websocket/server.ts'));

      expect(serverFile).toBeDefined();
      expect(path.isAbsolute(serverFile!.path)).toBe(true);
      expect(serverFile!.path).toBe(path.join(testOutputDir, 'backend', 'src', 'websocket', 'server.ts'));
    });

    it('should generate event-bridge.ts 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 generateWebSocketServer({ ...baseContext, extendedWorkflow });
      const bridgeFile = result.files.find(f => f.path.includes('event-bridge.ts'));

      expect(bridgeFile).toBeDefined();
    });
  });

  describe('WebSocket Server Implementation', () => {
    it('should import ws library', 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 generateWebSocketServer({ ...baseContext, extendedWorkflow });
      const serverFile = result.files.find(f => f.path.includes('/websocket/server.ts'));

      expect(serverFile!.content).toContain("Server as WebSocketServer");
      expect(serverFile!.content).toContain("from 'ws'");
    });

    it('should include RealtimeServer class', 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 generateWebSocketServer({ ...baseContext, extendedWorkflow });
      const serverFile = result.files.find(f => f.path.includes('/websocket/server.ts'));

      expect(serverFile!.content).toContain('export class RealtimeServer');
      expect(serverFile!.content).toContain('broadcast(');
    });

    it('should handle client connections and subscriptions', 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 generateWebSocketServer({ ...baseContext, extendedWorkflow });
      const serverFile = result.files.find(f => f.path.includes('/websocket/server.ts'));

      expect(serverFile!.content).toContain('private clients:');
      expect(serverFile!.content).toContain('subscribe');
      expect(serverFile!.content).toContain('unsubscribe');
    });

    it('should include singleton pattern', 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 generateWebSocketServer({ ...baseContext, extendedWorkflow });
      const serverFile = result.files.find(f => f.path.includes('/websocket/server.ts'));

      expect(serverFile!.content).toContain('let realtimeServerInstance');
      expect(serverFile!.content).toContain('export function initializeRealtimeServer');
      expect(serverFile!.content).toContain('export function getRealtimeServer');
    });
  });

  describe('Event Bridge Implementation', () => {
    it('should subscribe to all events', 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 generateWebSocketServer({ ...baseContext, extendedWorkflow });
      const bridgeFile = result.files.find(f => f.path.includes('event-bridge.ts'));

      expect(bridgeFile!.content).toContain("await eventBus.subscribe('user_created'");
      expect(bridgeFile!.content).toContain("await eventBus.subscribe('task_assigned'");
    });

    it('should broadcast events to WebSocket server', 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 generateWebSocketServer({ ...baseContext, extendedWorkflow });
      const bridgeFile = result.files.find(f => f.path.includes('event-bridge.ts'));

      expect(bridgeFile!.content).toContain('realtimeServer.broadcast');
      expect(bridgeFile!.content).toContain('getRealtimeServer()');
    });

    it('should import event bus', 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 generateWebSocketServer({ ...baseContext, extendedWorkflow });
      const bridgeFile = result.files.find(f => f.path.includes('event-bridge.ts'));

      expect(bridgeFile!.content).toContain("import { getEventBus } from '../events/event-bus'");
    });
  });

  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 generateWebSocketServer({ ...baseContext, extendedWorkflow });

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

    it('should generate valid TypeScript', 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 generateWebSocketServer({ ...baseContext, extendedWorkflow });

      for (const file of result.files) {
        expect(file.content).toContain('export');
        expect(file.content).not.toContain('[object Object]');
      }
    });
  });
});
