import { describe, test, expect, vi, beforeEach, afterEach } from 'vitest';
import { extractTextAndThumbnail } from '$lib/server/extraction';
import * as logger from '$lib/server/utils/logger';
import fs from 'fs';

describe('extraction.ts logging', () => {
	let logErrorSpy: any;
	
	beforeEach(() => {
		logErrorSpy = vi.spyOn(logger, 'logError').mockImplementation(() => {});
	});
	
	afterEach(() => {
		vi.restoreAllMocks();
	});
	
	test('should use logError for extraction failures', async () => {
		// Trigger extraction error with invalid URL
		try {
			await extractTextAndThumbnail('https://invalid-url-that-will-fail.com/test');
			// If it doesn't throw, that's fine too
		} catch (error) {
			// Expected - extraction of invalid URL should fail
		}
		
		// logError should have been called during retry/error handling
		expect(logErrorSpy).toHaveBeenCalled();
		const calls = logErrorSpy.mock.calls;
		expect(calls.length).toBeGreaterThan(0);
		
		// Verify at least one call has the expected format
		const errorCall = calls.find((call: any[]) => 
			call[0]?.match(/\[.*\]/) && call[1] !== undefined
		);
		expect(errorCall).toBeDefined();
		expect(errorCall[0]).toMatch(/\[.*\]/); // Has prefix like [Retry], [Extractor], etc
		expect(errorCall[1]).toBeDefined(); // Has error object
	});
	
	test('logs should not contain [object Object]', async () => {
		const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
		const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
		
		// Trigger extraction error
		try {
			await extractTextAndThumbnail('https://invalid-url-that-will-fail.com/test');
		} catch (e) {
			// Expected
		}
		
		// Check all console.warn and console.error calls
		const allCalls = [
			...consoleWarnSpy.mock.calls,
			...consoleErrorSpy.mock.calls
		];
		
		const errorCalls = allCalls
			.map(call => call.join(' '))
			.filter(msg => msg.includes('[object Object]'));
		
		expect(errorCalls).toHaveLength(0);
	});
	
	test('logError should serialize error objects properly', async () => {
		// Create a mock error with complex structure
		const mockError = new Error('Test error');
		(mockError as any).customProp = { nested: 'value' };
		
		// Call logError directly to verify it handles complex errors
		logger.logError('[Test] Test message', mockError);
		
		expect(logErrorSpy).toHaveBeenCalledWith('[Test] Test message', mockError);
		
		// Verify the actual logger implementation doesn't produce [object Object]
		const consoleErrorSpy = vi.spyOn(console, 'error');
		vi.restoreAllMocks();
		
		// Call real logError
		logger.logError('[Test] Real test', mockError);
		
		const output = consoleErrorSpy.mock.calls
			.map(call => call.join(' '))
			.join(' ');
		
		// Should not contain [object Object]
		expect(output).not.toContain('[object Object]');
	});
});
