import { describe, it, expect, vi, beforeEach } from 'vitest';
import { PromptEnhancementService } from '../PromptEnhancementService';
import type { AgentResult } from '../types';

// Mock the agents module
vi.mock('../agents', () => ({
  getAgent: vi.fn(() => ({
    templateType: 'general',
    enhance: vi.fn(),
  })),
}));

describe('PromptEnhancementService', () => {
  let service: PromptEnhancementService;
  const mockApiKey = 'test-gemini-api-key';

  beforeEach(() => {
    vi.clearAllMocks();
    service = new PromptEnhancementService(mockApiKey);
  });

  describe('constructor', () => {
    it('should throw error when API key is missing', () => {
      expect(() => new PromptEnhancementService('')).toThrow('Gemini API key is required');
    });

    it('should create instance with valid API key', () => {
      expect(service).toBeInstanceOf(PromptEnhancementService);
    });
  });

  describe('enhancePrompt', () => {
    it('should reject empty prompts', async () => {
      const result = await service.enhancePrompt('');
      expect(result.success).toBe(false);
      expect(result.error).toBe('Prompt cannot be empty');
    });

    it('should reject prompts exceeding 5000 characters', async () => {
      const longPrompt = 'a'.repeat(5001);
      const result = await service.enhancePrompt(longPrompt);
      expect(result.success).toBe(false);
      expect(result.error).toContain('exceeds maximum length');
    });

    it('should successfully enhance valid prompt', async () => {
      const { getAgent } = await import('../agents');
      const mockAgent = {
        templateType: 'general',
        enhance: vi.fn().mockResolvedValue({
          success: true,
          enhancedPrompt: 'A beautiful sunset over the ocean with vibrant colors',
          appliedTemplate: 'general',
          enhancements: ['Added detailed descriptions'],
        } as AgentResult),
      };
      vi.mocked(getAgent).mockReturnValue(mockAgent);

      const result = await service.enhancePrompt('sunset');
      expect(result.success).toBe(true);
      expect(result.enhancedPrompt).toBe('A beautiful sunset over the ocean with vibrant colors');
      expect(result.appliedTemplate).toBe('general');
    });

    it('should handle agent enhancement failure', async () => {
      const { getAgent } = await import('../agents');
      const mockAgent = {
        templateType: 'general',
        enhance: vi.fn().mockResolvedValue({
          success: false,
          error: 'Enhancement failed',
          enhancements: [],
        } as AgentResult),
      };
      vi.mocked(getAgent).mockReturnValue(mockAgent);

      const result = await service.enhancePrompt('sunset');
      expect(result.success).toBe(false);
      expect(result.error).toBe('Enhancement failed');
    });

    it('should truncate enhanced prompt exceeding 2000 characters', async () => {
      const { getAgent } = await import('../agents');
      const longEnhancedPrompt = 'enhanced '.repeat(300); // > 2000 chars
      const mockAgent = {
        templateType: 'general',
        enhance: vi.fn().mockResolvedValue({
          success: true,
          enhancedPrompt: longEnhancedPrompt,
          appliedTemplate: 'general',
          enhancements: [],
        } as AgentResult),
      };
      vi.mocked(getAgent).mockReturnValue(mockAgent);

      const result = await service.enhancePrompt('sunset');
      expect(result.success).toBe(true);
      expect(result.enhancedPrompt?.length).toBe(2000);
    });

    it('should pass options to agent', async () => {
      const { getAgent } = await import('../agents');
      const mockEnhance = vi.fn().mockResolvedValue({
        success: true,
        enhancedPrompt: 'Enhanced',
        appliedTemplate: 'photorealistic',
        enhancements: [],
      } as AgentResult);
      const mockAgent = {
        templateType: 'photorealistic',
        enhance: mockEnhance,
      };
      vi.mocked(getAgent).mockReturnValue(mockAgent);

      await service.enhancePrompt('sunset', {
        template: 'photorealistic',
        tags: ['landscape', 'nature'],
      });

      expect(mockEnhance).toHaveBeenCalledWith('sunset', {
        template: 'photorealistic',
        tags: ['landscape', 'nature'],
      });
    });

    it('should include detected language in result', async () => {
      const { getAgent } = await import('../agents');
      const mockAgent = {
        templateType: 'general',
        enhance: vi.fn().mockResolvedValue({
          success: true,
          enhancedPrompt: 'Enhanced prompt',
          detectedLanguage: 'Spanish',
          appliedTemplate: 'general',
          enhancements: [],
        } as AgentResult),
      };
      vi.mocked(getAgent).mockReturnValue(mockAgent);

      const result = await service.enhancePrompt('hermosa puesta de sol');
      expect(result.success).toBe(true);
      expect(result.detectedLanguage).toBe('Spanish');
    });

    it('should handle exceptions gracefully', async () => {
      const { getAgent } = await import('../agents');
      const mockAgent = {
        templateType: 'general',
        enhance: vi.fn().mockRejectedValue(new Error('Network error')),
      };
      vi.mocked(getAgent).mockReturnValue(mockAgent);

      const result = await service.enhancePrompt('sunset');
      expect(result.success).toBe(false);
      expect(result.error).toBe('Network error');
    });

    it('should return original prompt in all results', async () => {
      const originalPrompt = 'test prompt';
      const result = await service.enhancePrompt(originalPrompt);
      expect(result.originalPrompt).toBe(originalPrompt);
    });
  });
});
