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

// Create a mock models.list function that we can control
const mockModelsList = vi.fn();

// Mock OpenAI module BEFORE importing llm.ts
vi.mock('openai', () => ({
	default: class MockOpenAI {
		models = {
			list: mockModelsList
		};
	}
}));

// Mock env so tests pass in environments without .env (e.g. Docker CI builds)
vi.mock('$env/dynamic/private', () => ({
	env: {
		OPENAI_BASE_URL: 'http://localhost:11434/v1',
		OPENAI_API_KEY: 'test-key',
		LLM_MODEL: 'test-model',
		LLM_REQUEST_TIMEOUT_MS: undefined
	}
}));

// Import AFTER mocking
import { checkLLMHealth, checkModelAvailability } from '$lib/server/llm';

describe('llm.ts logging', () => {
	let logErrorSpy: any;
	let consoleErrorSpy: any;

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

	afterEach(() => {
		vi.restoreAllMocks();
	});

	test('should use logError on health check failure', async () => {
		// Mock OpenAI to throw an error
		const mockError = new Error('Connection failed');
		mockModelsList.mockRejectedValueOnce(mockError);

		const result = await checkLLMHealth();

		expect(result).toBe(false);
		expect(logErrorSpy).toHaveBeenCalledWith('[LLM] Health check failed', mockError);
	});

	test('should use logError on model availability check failure', async () => {
		const mockError = new Error('Network error');
		mockModelsList.mockRejectedValueOnce(mockError);

		const result = await checkModelAvailability('test-model');

		expect(result.available).toBe(false);
		expect(result.message).toContain('Failed to check model availability');
		expect(logErrorSpy).toHaveBeenCalledWith('[LLM] Model availability check failed', mockError);
	});

	test('should not log [object Object] for errors', async () => {
		const mockError = new Error('Test error');
		mockModelsList.mockRejectedValueOnce(mockError);

		await checkLLMHealth();

		// Verify console.error was never called with [object Object]
		const errorCalls = consoleErrorSpy.mock.calls
			.map((call: any[]) => call.join(' '))
			.filter((msg: string) => msg.includes('[object Object]'));

		expect(errorCalls).toHaveLength(0);
	});

	test('should serialize error details properly', async () => {
		const complexError = {
			code: 'ERR_CONNECTION',
			message: 'Failed to connect to LLM service',
			details: { host: 'localhost', port: 11434 }
		};
		mockModelsList.mockRejectedValueOnce(complexError);

		await checkModelAvailability('test-model');

		expect(logErrorSpy).toHaveBeenCalledWith('[LLM] Model availability check failed', complexError);
	});
});
