import 'reflect-metadata';
import { container } from 'tsyringe';
import { TaskClassifierService } from '../../../src/services/nlp/classifiers/task-classifier.service';
import { OpenAIService } from '../../../src/services/ai/openai.service';

// Mock OpenAIService
jest.mock('../../../src/services/ai/openai.service');

describe('TaskClassifierService', () => {
  let service: TaskClassifierService;
  let mockOpenAIService: jest.Mocked<OpenAIService>;

  beforeEach(() => {
    jest.clearAllMocks();
    container.clearInstances();

    // Create mock OpenAI service
    mockOpenAIService = {
      complete: jest.fn(),
    } as any;

    // Register mock with container
    container.registerInstance(OpenAIService, mockOpenAIService);

    // Create service
    service = container.resolve(TaskClassifierService);
  });

  describe('classify', () => {
    it('should classify task type correctly', async () => {
      // Arrange
      const text = 'Add new user registration feature with email verification';
      const entities = {
        title: 'User registration feature',
        description: 'Implement user registration with email verification',
      };

      mockOpenAIService.complete.mockResolvedValue({
        content: JSON.stringify({
          taskType: 'feature',
          subType: 'authentication',
          confidence: 0.9,
        }),
        usage: { totalTokens: 100 },
      });

      // Act
      const result = await service.classify({ text, entities, language: 'en' });

      // Assert
      expect(result.taskType).toBe('feature');
      expect(result.subType).toBe('authentication');
      expect(result.confidence).toBeGreaterThan(0.8);
    });

    it('should classify bug reports', async () => {
      // Arrange
      const text = 'Fix the login button not working on mobile devices';
      const entities = {
        title: 'Fix login button on mobile',
        priority: 'high',
      };

      mockOpenAIService.complete.mockResolvedValue({
        content: JSON.stringify({
          taskType: 'bug',
          severity: 'high',
          affectedArea: 'authentication',
          confidence: 0.95,
        }),
        usage: { totalTokens: 100 },
      });

      // Act
      const result = await service.classify({ text, entities, language: 'en' });

      // Assert
      expect(result.taskType).toBe('bug');
      expect(result.severity).toBe('high');
      expect(result.affectedArea).toBe('authentication');
    });

    it('should classify improvements', async () => {
      // Arrange
      const text = 'Optimize database queries to improve page load time';
      const entities = {
        title: 'Optimize database queries',
        description: 'Performance improvement',
      };

      mockOpenAIService.complete.mockResolvedValue({
        content: JSON.stringify({
          taskType: 'improvement',
          category: 'performance',
          impact: 'medium',
          confidence: 0.85,
        }),
        usage: { totalTokens: 100 },
      });

      // Act
      const result = await service.classify({ text, entities, language: 'en' });

      // Assert
      expect(result.taskType).toBe('improvement');
      expect(result.category).toBe('performance');
      expect(result.impact).toBe('medium');
    });

    it('should detect priority from context', async () => {
      // Arrange
      const text = 'URGENT: Critical security patch needed ASAP';
      const entities = {
        title: 'Security patch',
        priority: 'critical',
      };

      mockOpenAIService.complete.mockResolvedValue({
        content: JSON.stringify({
          taskType: 'security',
          priority: 'critical',
          urgency: 'immediate',
          confidence: 0.98,
        }),
        usage: { totalTokens: 100 },
      });

      // Act
      const result = await service.classify({ text, entities, language: 'en' });

      // Assert
      expect(result.priority).toBe('critical');
      expect(result.urgency).toBe('immediate');
      expect(result.confidence).toBeGreaterThan(0.95);
    });

    it('should analyze sentiment for urgency', async () => {
      // Arrange
      const text = 'This is blocking the entire team! We need this fixed NOW!';
      const entities = {
        title: 'Blocking issue',
      };

      mockOpenAIService.complete.mockResolvedValue({
        content: JSON.stringify({
          taskType: 'blocker',
          sentiment: 'negative',
          urgency: 'critical',
          emotionalTone: 'frustrated',
          confidence: 0.92,
        }),
        usage: { totalTokens: 100 },
      });

      // Act
      const result = await service.classify({ text, entities, language: 'en' });

      // Assert
      expect(result.urgency).toBe('critical');
      expect(result.sentiment).toBe('negative');
      expect(result.emotionalTone).toBe('frustrated');
    });

    it('should estimate complexity', async () => {
      // Arrange
      const text = 'Refactor the entire authentication system to use OAuth 2.0 with multiple providers';
      const entities = {
        title: 'Refactor authentication system',
        estimatedHours: 40,
      };

      mockOpenAIService.complete.mockResolvedValue({
        content: JSON.stringify({
          taskType: 'refactoring',
          complexity: 'high',
          estimatedEffort: 'large',
          riskLevel: 'medium',
          confidence: 0.8,
        }),
        usage: { totalTokens: 100 },
      });

      // Act
      const result = await service.classify({ text, entities, language: 'en' });

      // Assert
      expect(result.complexity).toBe('high');
      expect(result.estimatedEffort).toBe('large');
      expect(result.riskLevel).toBe('medium');
    });

    it('should identify technical areas', async () => {
      // Arrange
      const text = 'Update React components to use TypeScript and add unit tests';
      const entities = {
        title: 'Update React components',
        tags: ['frontend', 'testing'],
      };

      mockOpenAIService.complete.mockResolvedValue({
        content: JSON.stringify({
          taskType: 'technical-debt',
          technicalAreas: ['frontend', 'typescript', 'testing'],
          frameworks: ['react'],
          confidence: 0.88,
        }),
        usage: { totalTokens: 100 },
      });

      // Act
      const result = await service.classify({ text, entities, language: 'en' });

      // Assert
      expect(result.technicalAreas).toContain('frontend');
      expect(result.technicalAreas).toContain('typescript');
      expect(result.frameworks).toContain('react');
    });

    it('should classify documentation tasks', async () => {
      // Arrange
      const text = 'Write API documentation for the new endpoints';
      const entities = {
        title: 'API documentation',
      };

      mockOpenAIService.complete.mockResolvedValue({
        content: JSON.stringify({
          taskType: 'documentation',
          documentationType: 'api',
          priority: 'medium',
          confidence: 0.9,
        }),
        usage: { totalTokens: 100 },
      });

      // Act
      const result = await service.classify({ text, entities, language: 'en' });

      // Assert
      expect(result.taskType).toBe('documentation');
      expect(result.documentationType).toBe('api');
    });

    it('should handle multi-language classification', async () => {
      // Arrange
      const text = 'Corregir el error en el sistema de pagos'; // Spanish
      const entities = {
        title: 'Error sistema de pagos',
      };

      mockOpenAIService.complete.mockResolvedValue({
        content: JSON.stringify({
          taskType: 'bug',
          affectedArea: 'payments',
          language: 'es',
          confidence: 0.85,
        }),
        usage: { totalTokens: 100 },
      });

      // Act
      const result = await service.classifyTask(text, entities, 'es');

      // Assert
      expect(result.taskType).toBe('bug');
      expect(result.affectedArea).toBe('payments');
      expect(result.language).toBe('es');
    });

    it('should provide confidence scores', async () => {
      // Arrange
      const text = 'Maybe look into improving something';
      const entities = {
        title: 'Improvement task',
      };

      mockOpenAIService.complete.mockResolvedValue({
        content: JSON.stringify({
          taskType: 'improvement',
          confidence: 0.4,
          uncertaintyReason: 'vague description',
        }),
        usage: { totalTokens: 100 },
      });

      // Act
      const result = await service.classify({ text, entities, language: 'en' });

      // Assert
      expect(result.confidence).toBeLessThan(0.5);
      expect(result.uncertaintyReason).toBe('vague description');
    });

    it('should handle classification errors', async () => {
      // Arrange
      const text = 'Test task';
      const entities = { title: 'Test' };

      mockOpenAIService.complete.mockRejectedValue(new Error('Classification failed'));

      // Act & Assert
      await expect(service.classify({ text, entities, language: 'en' })).rejects.toThrow('Classification failed');
    });

    it('should classify research tasks', async () => {
      // Arrange
      const text = 'Research and evaluate different caching strategies for the API';
      const entities = {
        title: 'Research caching strategies',
      };

      mockOpenAIService.complete.mockResolvedValue({
        content: JSON.stringify({
          taskType: 'research',
          researchArea: 'performance',
          deliverables: ['evaluation report', 'recommendations'],
          confidence: 0.87,
        }),
        usage: { totalTokens: 100 },
      });

      // Act
      const result = await service.classify({ text, entities, language: 'en' });

      // Assert
      expect(result.taskType).toBe('research');
      expect(result.researchArea).toBe('performance');
      expect(result.deliverables).toContain('evaluation report');
    });
  });

  describe('pattern-based classification', () => {
    it('should detect bug patterns', async () => {
      // Arrange
      const text = 'BUG: Application crashes when user clicks submit';
      const entities = { title: 'Application crash' };

      mockOpenAIService.complete.mockResolvedValue({
        content: JSON.stringify({
          taskType: 'bug',
          patternMatch: true,
          confidence: 0.99,
        }),
        usage: { totalTokens: 100 },
      });

      // Act
      const result = await service.classify({ text, entities, language: 'en' });

      // Assert
      expect(result.taskType).toBe('bug');
      expect(result.patternMatch).toBe(true);
      expect(result.confidence).toBeGreaterThan(0.95);
    });

    it('should detect feature patterns', async () => {
      // Arrange
      const text = 'FEATURE REQUEST: Add dark mode to the application';
      const entities = { title: 'Add dark mode' };

      mockOpenAIService.complete.mockResolvedValue({
        content: JSON.stringify({
          taskType: 'feature',
          requestType: 'enhancement',
          patternMatch: true,
          confidence: 0.95,
        }),
        usage: { totalTokens: 100 },
      });

      // Act
      const result = await service.classify({ text, entities, language: 'en' });

      // Assert
      expect(result.taskType).toBe('feature');
      expect(result.requestType).toBe('enhancement');
      expect(result.patternMatch).toBe(true);
    });
  });
});