
import newman from 'newman';
import {NewmanRunner} from '../../src/newman/newman-test.js';
import {LogWrapper} from '../../src/service/log-wrapper.js';


// Mocking newman and LogWrapper
jest.mock('newman');
jest.mock('../../src/service/log-wrapper.ts');

describe('NewmanRunner', () => {
	let newmanRunner: NewmanRunner;

	const mockCollection = {
		info: { name: 'Test Collection', version: '1.0', schema: 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json' },
		item: [],
	};

	beforeEach(() => {
		newmanRunner = new NewmanRunner(mockCollection);
	});

	it('should resolve and log info when newman run is successful', async () => {
		const mockSummary = {
			run: {
				executions: [],
				stats: { assertions: { total: 10, failed: 0 } },
				failures: [],
				timings: { started: 1000, completed: 2000 },
			},
			collection: { id: '123', name: 'Test Collection' },
		};


		(newman.run as jest.Mock).mockImplementation((options, callback) => {
			callback(null, mockSummary);
		});

		const result = await newmanRunner.run();

		expect(LogWrapper.logInfo).toHaveBeenCalledWith('0215', 'Test Collection');
		expect(LogWrapper.logDebug).toHaveBeenCalledWith('0003', 'Newman run completed. Processing results.');
		expect(result).toEqual({
			id: '123',
			name: 'Test Collection',
			timestamp: 2000,
			totalPass: 10,
			totalFail: 0,
			status: 'finished',
			startedAt: 1000,
			totalTime: 1000,
			results: [],
		});
	});

	it('should reject and log error when newman run fails', async () => {
		const mockError = new Error('Test error');


		(newman.run as jest.Mock).mockImplementation((options, callback) => {
			callback(mockError, null);
		});

		await expect(newmanRunner.run()).rejects.toThrow('Error running tests');

		expect(LogWrapper.logError).toHaveBeenCalledWith('0013', 'running tests', 'Test error');
	});

	it('should reject and log error when processing test results fails', async () => {
		const mockSummary = {
			run: {
				executions: [],
				stats: { assertions: { total: 10, failed: 2 } },
				failures: [],
				timings: { started: 1000, completed: 2000 },
			},
			collection: { id: '123', name: 'Test Collection' },
		};


		(newman.run as jest.Mock).mockImplementation((options, callback) => {
			callback(null, mockSummary);
		});


		jest.spyOn(newmanRunner as any, 'getExecutionResults').mockImplementation(() => {
			throw new Error('Test processing error');
		});

		await expect(newmanRunner.run()).rejects.toThrow('Error processing test results');

		expect(LogWrapper.logError).toHaveBeenCalledWith('0013', 'processing test results', 'Test processing error');
	});

	it('should format execution results correctly', () => {
		const mockExecution = {
			id: '1',
			item: { name: 'Test Item' },
			request: {
				url: { toString: () => 'http://example.com' },
				method: 'GET',
				headers: [],
			},
			response: {
				code: 200,
				status: 'OK',
				responseTime: 100,
				responseSize: 500,
				body: 'Response body',
			},
			assertions: [
				{ assertion: 'should return 200', error: null },
				{ assertion: 'should contain header', error: { message: 'Missing header' } },
			],
		};

		const result = (newmanRunner as any).getExecutionResults([mockExecution]);

		expect(result).toEqual([
			{
				id: '1',
				name: 'Test Item',
				url: 'http://example.com',
				method: 'GET',
				header: [],
				time: 100,
				responseCode: {
					code: 200,
					name: 'OK',
					time: 100,
					size: 500,
				},
				responseHeaders: null,
				response: 'Response body',
				allTests:  [
					{
						'should return 200': {
							'status': true
						}
					},
					{
						'should contain header': {
							'error': {
								'message': 'Missing header'
							},
							'status': false
						}
					}
				],
			},
		]);
	});
	it('should format execution results correctly - default response code', () => {
		const mockExecution = {
			id: '1',
			item: { name: 'Test Item' },
			request: {
				url: { toString: () => 'http://example.com' },
				method: 'GET',
				headers: [],
			},
			response: {
				body: 'Response body',
			},
			assertions: [
				{ assertion: 'should return 200', error: null },
				{ assertion: 'should contain header', error: { message: 'Missing header' } },
			],
		};

		const result = (newmanRunner as any).getExecutionResults([mockExecution]);

		expect(result).toEqual([
			{
				id: '1',
				name: 'Test Item',
				url: 'http://example.com',
				method: 'GET',
				header: [],
				time: 0,
				responseCode: {
					code: 408,
					name: 'Request Timed out',
					time: 0,
					size: 0,
				},
				responseHeaders: null,
				response: 'Response body',
				allTests:  [
					{
						'should return 200': {
							'status': true
						}
					},
					{
						'should contain header': {
							'error': {
								'message': 'Missing header'
							},
							'status': false
						}
					}
				],
			},
		]);
	});
	it('should format execution results correctly for not having response body', () => {
		const mockExecution = {
			id: '1',
			item: { name: 'Test Item' },
			request: {
				url: { toString: () => 'http://example.com' },
				method: 'GET',
				headers: [],
			},
			response: {
				code: 200,
				status: 'OK',
				responseTime: 100,
				responseSize: 500,
			},
			assertions: [
				{ assertion: 'should return 200', error: null },
				{ assertion: 'should contain header', error: { message: 'Missing header' } },
			],
		};

		const result = (newmanRunner as any).getExecutionResults([mockExecution]);

		expect(result).toEqual([
			{
				id: '1',
				name: 'Test Item',
				url: 'http://example.com',
				method: 'GET',
				header: [],
				time: 100,
				responseCode: {
					code: 200,
					name: 'OK',
					time: 100,
					size: 500,
				},
				responseHeaders: null,
				response: 'Response unavailable',
				allTests:  [
					{
						'should return 200': {
							'status': true
						}
					},
					{
						'should contain header': {
							'error': {
								'message': 'Missing header'
							},
							'status': false
						}
					}
				],
			},
		]);
	});
	it('should format execution results correctly for not having response stream', () => {
		const mockExecution = {
			id: '1',
			item: { name: 'Test Item' },
			request: {
				url: { toString: () => 'http://example.com' },
				method: 'GET',
				headers: [],
			},
			response: {
				code: 200,
				status: 'OK',
				responseTime: 100,
				responseSize: 500,
				stream: '<Buffer 7b 22 73 74 61 74 75 73 22 3a 22 73 75 63 63 65 73 73 22 7d>'
			},
			assertions: [
				{ assertion: 'should return 200', error: null },
				{ assertion: 'should contain header', error: { message: 'Missing header' } },
			],
		};

		const result = (newmanRunner as any).getExecutionResults([mockExecution]);

		expect(result).toEqual([
			{
				id: '1',
				name: 'Test Item',
				url: 'http://example.com',
				method: 'GET',
				header: [],
				time: 100,
				responseCode: {
					code: 200,
					name: 'OK',
					time: 100,
					size: 500,
				},
				responseHeaders: null,
				response: '<Buffer 7b 22 73 74 61 74 75 73 22 3a 22 73 75 63 63 65 73 73 22 7d>',
				allTests:  [
					{
						'should return 200': {
							'status': true
						}
					},
					{
						'should contain header': {
							'error': {
								'message': 'Missing header'
							},
							'status': false
						}
					}
				],
			},
		]);
	});
});
