import { describe, test, expect, vi, beforeEach, afterEach } from 'vitest';

// Mock parser to avoid LLM calls
vi.mock('$lib/server/parser', () => ({
  extractRecipe: vi.fn().mockResolvedValue({
    name: 'Test Recipe',
    ingredients: [],
    instructions: 'Test instructions',
    servings: 4
  }),
  detectRecipe: vi.fn().mockResolvedValue(true)
}));

// Mock tandoor to avoid API calls
vi.mock('$lib/server/tandoor', () => ({
  uploadRecipeWithIngredientsDTO: vi.fn().mockResolvedValue({ id: 123 }),
  uploadRecipeImage: vi.fn().mockResolvedValue(true)
}));

import { queueManager } from '$lib/server/queue/QueueManager';
import * as extraction from '$lib/server/extraction';
import { queueProcessor } from '$lib/server/queue/QueueProcessor';

describe('QueueProcessor logging', () => {
  
  let consoleErrorSpy: any;
  
  beforeEach(async () => {
    // Stop processor first
    queueProcessor.stop();
    
    // Clear queue
    const items = queueManager.getAll();
    items.forEach(item => queueManager.remove(item.id));
    
    // Setup console.error spy
    consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
    
    // Give time for cleanup
    await new Promise(resolve => setTimeout(resolve, 100));
  });
  
  afterEach(() => {
    queueProcessor.stop();
    consoleErrorSpy.mockRestore();
  });
  
  test('error logs should be properly serialized (no [object Object])', async () => {
    // Create complex error object
    const complexError = new Error('Test extraction error');
    (complexError as any).code = 'ERR_TEST';
    (complexError as any).details = { phase: 'extraction', retries: 3 };
    
    // Mock extraction to fail BEFORE starting processor
    const extractSpy = vi.spyOn(extraction, 'extractTextAndThumbnail');
    extractSpy.mockRejectedValueOnce(complexError);
    
    const item = queueManager.enqueue('https://instagram.com/p/TEST');
    queueProcessor.start();
    
    // Wait for error status
    await vi.waitFor(() => {
      const updated = queueManager.get(item.id);
      return updated?.status === 'error' || updated?.status === 'unhealthy';
    }, { timeout: 5000 });
    
    // Stop processor
    queueProcessor.stop();
    
    // Wait a bit for all logs to finish
    await new Promise(resolve => setTimeout(resolve, 100));
    
    // Check that console.error doesn't contain [object Object]
    const allCalls = consoleErrorSpy.mock.calls.map((call: any[]) => 
      call.map(arg => {
        if (arg && typeof arg === 'object' && arg.message) {
          return arg.message; // Handle Error objects
        }
        return String(arg);
      }).join(' ')
    );
    
    const hasObjectObject = allCalls.some((msg: string) => msg.includes('[object Object]'));
    expect(hasObjectObject).toBe(false);
    
    // Verify QueueProcessor logs are present
    const queueProcessorLogs = allCalls.filter((msg: string) =>
      msg.includes('[QueueProcessor]')
    );
    
    expect(queueProcessorLogs.length).toBeGreaterThan(0);
  });
});
