/**
 * Tests for WebSocket Client Generator
 */

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

describe('WebSocket Client 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 generateWebSocketClient(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' },
          frontend: { framework: 'react', language: 'typescript', styling: 'tailwind', state_management: 'context' },
          cache: { provider: 'redis', use: 'local' },
        },
      };

      const result = await generateWebSocketClient({ ...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' },
          frontend: { framework: 'react', language: 'typescript', styling: 'tailwind', state_management: 'context' },
        },
        events: {
          user_created: {
            description: 'User created',
            payload: { user_id: 'string' },
          },
        },
      };

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

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

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

  describe('File Generation', () => {
    it('should generate websocket-client.ts file', async () => {
      const extendedWorkflow = {
        ...baseWorkflow.workflow as any,
        technology: {
          backend: { framework: 'express', language: 'typescript' },
          frontend: { framework: 'react', language: 'typescript', styling: 'tailwind', state_management: 'context' },
          cache: { provider: 'redis', use: 'local' },
        },
        events: {
          user_created: {
            description: 'User created',
            payload: { user_id: 'string' },
          },
        },
      };

      const result = await generateWebSocketClient({ ...baseContext, extendedWorkflow });
      const clientFile = result.files.find(f => f.path.includes('websocket-client.ts'));

      expect(clientFile).toBeDefined();
      expect(path.isAbsolute(clientFile!.path)).toBe(true);
      expect(clientFile!.path).toBe(path.join(testOutputDir, 'frontend', 'src', 'lib', 'websocket-client.ts'));
    });

    it('should generate useEvents.ts hook', async () => {
      const extendedWorkflow = {
        ...baseWorkflow.workflow as any,
        technology: {
          backend: { framework: 'express', language: 'typescript' },
          frontend: { framework: 'react', language: 'typescript', styling: 'tailwind', state_management: 'context' },
          cache: { provider: 'redis', use: 'local' },
        },
        events: {
          user_created: {
            description: 'User created',
            payload: { user_id: 'string' },
          },
        },
      };

      const result = await generateWebSocketClient({ ...baseContext, extendedWorkflow });
      const hookFile = result.files.find(f => f.path.includes('useEvents.ts'));

      expect(hookFile).toBeDefined();
    });

    it('should generate websocket-context.tsx provider', async () => {
      const extendedWorkflow = {
        ...baseWorkflow.workflow as any,
        technology: {
          backend: { framework: 'express', language: 'typescript' },
          frontend: { framework: 'react', language: 'typescript', styling: 'tailwind', state_management: 'context' },
          cache: { provider: 'redis', use: 'local' },
        },
        events: {
          user_created: {
            description: 'User created',
            payload: { user_id: 'string' },
          },
        },
      };

      const result = await generateWebSocketClient({ ...baseContext, extendedWorkflow });
      const contextFile = result.files.find(f => f.path.includes('websocket-context.tsx'));

      expect(contextFile).toBeDefined();
    });
  });

  describe('WebSocket Client Implementation', () => {
    it('should include WebSocketClient class', async () => {
      const extendedWorkflow = {
        ...baseWorkflow.workflow as any,
        technology: {
          backend: { framework: 'express', language: 'typescript' },
          frontend: { framework: 'react', language: 'typescript', styling: 'tailwind', state_management: 'context' },
          cache: { provider: 'redis', use: 'local' },
        },
        events: {
          user_created: {
            description: 'User created',
            payload: { user_id: 'string' },
          },
        },
      };

      const result = await generateWebSocketClient({ ...baseContext, extendedWorkflow });
      const clientFile = result.files.find(f => f.path.includes('websocket-client.ts'));

      expect(clientFile!.content).toContain('export class WebSocketClient');
      expect(clientFile!.content).toContain('connect(');
      expect(clientFile!.content).toContain('subscribe(');
      expect(clientFile!.content).toContain('disconnect(');
    });

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

      const result = await generateWebSocketClient({ ...baseContext, extendedWorkflow });
      const clientFile = result.files.find(f => f.path.includes('websocket-client.ts'));

      expect(clientFile!.content).toContain('reconnectAttempts');
      expect(clientFile!.content).toContain('attemptReconnect');
    });

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

      const result = await generateWebSocketClient({ ...baseContext, extendedWorkflow });
      const clientFile = result.files.find(f => f.path.includes('websocket-client.ts'));

      expect(clientFile!.content).toContain('startHeartbeat');
      expect(clientFile!.content).toContain('stopHeartbeat');
    });
  });

  describe('React Hooks', () => {
    it('should generate useEvent hook', async () => {
      const extendedWorkflow = {
        ...baseWorkflow.workflow as any,
        technology: {
          backend: { framework: 'express', language: 'typescript' },
          frontend: { framework: 'react', language: 'typescript', styling: 'tailwind', state_management: 'context' },
          cache: { provider: 'redis', use: 'local' },
        },
        events: {
          user_created: {
            description: 'User created',
            payload: { user_id: 'string' },
          },
        },
      };

      const result = await generateWebSocketClient({ ...baseContext, extendedWorkflow });
      const hookFile = result.files.find(f => f.path.includes('useEvents.ts'));

      expect(hookFile!.content).toContain('export function useEvent');
      expect(hookFile!.content).toContain('EventPayloadMap');
    });

    it('should generate useEvents hook for all events', async () => {
      const extendedWorkflow = {
        ...baseWorkflow.workflow as any,
        technology: {
          backend: { framework: 'express', language: 'typescript' },
          frontend: { framework: 'react', language: 'typescript', styling: 'tailwind', state_management: 'context' },
          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 generateWebSocketClient({ ...baseContext, extendedWorkflow });
      const hookFile = result.files.find(f => f.path.includes('useEvents.ts'));

      expect(hookFile!.content).toContain('export function useEvents');
      expect(hookFile!.content).toContain('user_created:');
      expect(hookFile!.content).toContain('task_assigned:');
    });

    it('should import React hooks', async () => {
      const extendedWorkflow = {
        ...baseWorkflow.workflow as any,
        technology: {
          backend: { framework: 'express', language: 'typescript' },
          frontend: { framework: 'react', language: 'typescript', styling: 'tailwind', state_management: 'context' },
          cache: { provider: 'redis', use: 'local' },
        },
        events: {
          user_created: {
            description: 'User created',
            payload: { user_id: 'string' },
          },
        },
      };

      const result = await generateWebSocketClient({ ...baseContext, extendedWorkflow });
      const hookFile = result.files.find(f => f.path.includes('useEvents.ts'));

      expect(hookFile!.content).toContain("import { useEffect, useCallback } from 'react'");
    });
  });

  describe('Context Provider', () => {
    it('should generate WebSocketProvider component', async () => {
      const extendedWorkflow = {
        ...baseWorkflow.workflow as any,
        technology: {
          backend: { framework: 'express', language: 'typescript' },
          frontend: { framework: 'react', language: 'typescript', styling: 'tailwind', state_management: 'context' },
          cache: { provider: 'redis', use: 'local' },
        },
        events: {
          user_created: {
            description: 'User created',
            payload: { user_id: 'string' },
          },
        },
      };

      const result = await generateWebSocketClient({ ...baseContext, extendedWorkflow });
      const contextFile = result.files.find(f => f.path.includes('websocket-context.tsx'));

      expect(contextFile!.content).toContain('export function WebSocketProvider');
      expect(contextFile!.content).toContain('createContext');
    });

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

      const result = await generateWebSocketClient({ ...baseContext, extendedWorkflow });
      const contextFile = result.files.find(f => f.path.includes('websocket-context.tsx'));

      expect(contextFile!.content).toContain('export function useWebSocket');
      expect(contextFile!.content).toContain('useContext');
    });

    it('should support auto-connect option', async () => {
      const extendedWorkflow = {
        ...baseWorkflow.workflow as any,
        technology: {
          backend: { framework: 'express', language: 'typescript' },
          frontend: { framework: 'react', language: 'typescript', styling: 'tailwind', state_management: 'context' },
          cache: { provider: 'redis', use: 'local' },
        },
        events: {
          user_created: {
            description: 'User created',
            payload: { user_id: 'string' },
          },
        },
      };

      const result = await generateWebSocketClient({ ...baseContext, extendedWorkflow });
      const contextFile = result.files.find(f => f.path.includes('websocket-context.tsx'));

      expect(contextFile!.content).toContain('autoConnect');
    });
  });

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

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

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