import { describe, test, expect, vi, beforeEach } from 'vitest';
import { uploadRecipeWithIngredientsDTO, uploadRecipeImage } from '$lib/server/tandoor';
import * as logger from '$lib/server/utils/logger';

vi.mock('$lib/server/tandoor-config', () => ({
	tandoorConfig: {
		serverUrl: 'http://localhost:8000',
		token: 'test-token'
	}
}));

describe('tandoor logging', () => {
	let logErrorSpy: any;

	beforeEach(() => {
		vi.clearAllMocks();
		logErrorSpy = vi.spyOn(logger, 'logError');
	});

	test('should use logError on upload failure', async () => {
		vi.spyOn(global, 'fetch').mockRejectedValue(new Error('Network error'));

		const recipe = {
			name: 'Test Recipe',
			servings: 4,
			description: 'Test description',
			ingredients: [{ item: 'Flour', amount: '2', unit: 'cups' }],
			steps: ['Mix ingredients']
		};

		await uploadRecipeWithIngredientsDTO(recipe);

		expect(logErrorSpy).toHaveBeenCalledWith('[Tandoor] Fetch error', expect.any(Error));
	});

	test('should use logError on API error response', async () => {
		const errorBody = { detail: 'Invalid token' };
		vi.spyOn(global, 'fetch').mockResolvedValue({
			ok: false,
			status: 401,
			statusText: 'Unauthorized',
			json: vi.fn().mockResolvedValue(errorBody)
		} as any);

		const recipe = {
			name: 'Test Recipe',
			servings: 4,
			description: null,
			ingredients: null,
			steps: null
		};

		await uploadRecipeWithIngredientsDTO(recipe);

		expect(logErrorSpy).toHaveBeenCalledWith(
			expect.stringContaining('[Tandoor] API Error'),
			errorBody
		);
	});

	test('should use logError on recipe upload exception', async () => {
		const error = new Error('Upload failed');
		vi.spyOn(global, 'fetch').mockResolvedValue({
			ok: true,
			json: vi.fn().mockRejectedValue(error)
		} as any);

		const recipe = {
			name: 'Test Recipe',
			servings: 4,
			description: null,
			ingredients: null,
			steps: null
		};

		await uploadRecipeWithIngredientsDTO(recipe);

		expect(logErrorSpy).toHaveBeenCalledWith('[Tandoor] Fetch error', expect.any(Error));
	});

	test('should use logError on image upload failure', async () => {
		const error = new Error('Image upload failed');
		vi.spyOn(global, 'fetch').mockRejectedValue(error);

		const result = await uploadRecipeImage(123, 'https://example.com/image.jpg');

		expect(result.success).toBe(false);
		expect(logErrorSpy).toHaveBeenCalledWith('[Tandoor Upload] Exception', error);
	});

	test('should use logError instead of manual error logging', async () => {
		const error = new Error('Test error');
		vi.spyOn(global, 'fetch').mockRejectedValue(error);

		await uploadRecipeWithIngredientsDTO({
			name: 'Test',
			servings: null,
			description: null,
			ingredients: null,
			steps: null
		});

		// Verify logError was called (which handles stack trace serialization)
		expect(logErrorSpy).toHaveBeenCalledWith('[Tandoor] Fetch error', error);

		// logError itself logs stack traces, which is expected behavior
		// The key is that tandoor.ts uses logError instead of manual logging
	});

	test('should serialize complex error objects', async () => {
		const complexError = {
			code: 'ERR_VALIDATION',
			message: 'Invalid recipe data',
			details: { field: 'name', reason: 'required' }
		};

		vi.spyOn(global, 'fetch').mockResolvedValue({
			ok: false,
			status: 400,
			statusText: 'Bad Request',
			json: vi.fn().mockResolvedValue(complexError)
		} as any);

		await uploadRecipeWithIngredientsDTO({
			name: 'Test',
			servings: null,
			description: null,
			ingredients: null,
			steps: null
		});

		expect(logErrorSpy).toHaveBeenCalledWith(
			expect.stringContaining('[Tandoor] API Error'),
			complexError
		);
	});
});
