import {executeTest, writeTestResultsToFile} from './projects-testers';
import { TestManager } from '@apic/studio-test';
import { showSuccess, showError, showInfo } from '../../helpers/common/message-helper';
import { DebugManager } from '../../debug/debug-manager';
import {
	EXECUTING_TEST,
	EXECUTING_TESTS_SUCCESS,
	TESTING,
	LINE, OVERALL_TEST_SUMMARY, ERROR_IN_EXECUTING_TEST, FAILED_TESTS, EMPTY_RESULT,
} from '../../constants/message-constants';
let mockExit: jest.SpyInstance;



beforeEach(() => {
	// @ts-ignore
	mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {
	});
});

afterEach(() => {
	mockExit.mockRestore();
});

jest.mock('@apic/studio-test', () => {
	return {
		TestManager: jest.fn().mockImplementation(() => {
			return {
				processFile: jest.fn(),
			};
		}),
	};
});

jest.mock('../../helpers/common/message-helper.js', () => ({
	showSuccess: jest.fn(),
	showError: jest.fn(),
	showInfo: jest.fn(),
}));
		

jest.mock('../../debug/debug-manager');

const debugManagerMock = {
	isDebugEnabled: jest.fn(),
};
(DebugManager.getInstance as jest.Mock).mockReturnValue(debugManagerMock);

describe('Projects Testers test suite', () => {
	let processFileMock: jest.Mock;

	beforeEach(() => {
		jest.clearAllMocks();
		processFileMock = jest.fn();
		(TestManager as jest.Mock).mockImplementation(() => ({
			processFile: processFileMock,
		}));
	});

	it('should show info when executing tests in debug mode', async () => {
		debugManagerMock.isDebugEnabled.mockReturnValue(true);
		processFileMock.mockResolvedValue({});
		await executeTest(Buffer.from('test zip buffer'));

		expect(showInfo).toHaveBeenCalledWith(EXECUTING_TEST);
	});

	it('should not show info when debug mode is disabled', async () => {
		debugManagerMock.isDebugEnabled.mockReturnValue(false);
		processFileMock.mockResolvedValue({});
		await executeTest(Buffer.from('test zip buffer'));

		expect(showInfo).toHaveBeenCalledTimes(0);
	});

	it('should show error if the result is null', async () => {
		processFileMock.mockResolvedValue(null);
		try{
			await executeTest(Buffer.from('test zip buffer'));
		}catch(error){
			// @ts-ignore
			expect(error.message).toEqual(ERROR_IN_EXECUTING_TEST);
		}

	});

	it('should call prepareTestResults with the correct result', async () => {
		const mockResult = [{ name: 'test1', totalPass: 2, totalFail: 1, status: 'Passed', results: [] }];
		processFileMock.mockResolvedValue(mockResult);
		await executeTest(Buffer.from('test zip buffer'));
		expect(showInfo).toHaveBeenCalledWith(LINE);
		expect(showInfo).toHaveBeenCalledWith(TESTING);
		expect(showInfo).toHaveBeenCalledWith(LINE);
		expect(showSuccess).toHaveBeenCalledWith(EXECUTING_TESTS_SUCCESS);

	});

	it('should call overall test summary', async () => {
		const mockResult = [{ name: 'test1', totalPass: 2, totalFail: 0, status: 'Passed', results: [] },{ name: 'test2', totalPass: 3, totalFail: 1, status: 'Passed', results: [] }];
		processFileMock.mockResolvedValue(mockResult);
		await executeTest(Buffer.from('test zip buffer'));
		expect(showInfo).toHaveBeenCalledWith(LINE);
		expect(showInfo).toHaveBeenCalledWith(TESTING);
		expect(showInfo).toHaveBeenCalledWith(LINE);
		expect(showSuccess).toHaveBeenCalledWith(EXECUTING_TESTS_SUCCESS);
		expect(showInfo).toHaveBeenCalledWith(OVERALL_TEST_SUMMARY);
	});


	it('should call writeTestResultsToFile', async () => {
		const mockResult = [{name: 'test1', totalPass: 2, totalFail: 1, status: 'Passed', results: []}, {
			name: 'test2',
			totalPass: 3,
			totalFail: 1,
			status: 'Failed',
			results: []
		}];
		processFileMock.mockResolvedValue(mockResult);
		const writeJsonSpy = jest.spyOn(require('../project/projects-testers'), 'writeTestResultsToFile').mockResolvedValue(undefined);
		try{
			await executeTest(Buffer.from('test zip buffer'));
		}catch (error){
			expect(writeJsonSpy).toHaveBeenCalled();
			// @ts-ignore
			expect(error.message).toEqual(FAILED_TESTS);
		}


	});
	it('should show error when an exception occurs', async () => {
		const errorMessage = 'Test error';
		processFileMock.mockRejectedValue(new Error(errorMessage));
		try{
			await executeTest(Buffer.from('test zip buffer'));
		}catch (error){
			expect(showError).not.toHaveBeenCalledWith(`${errorMessage}`);
		}


	});

	it('should handle an empty result array gracefully', async () => {
		processFileMock.mockResolvedValue([]);
		await executeTest(Buffer.from('test zip buffer'));
		expect(showError).toHaveBeenCalledWith(EMPTY_RESULT);
	});

	it('should throw and handle an error if processFile throws an error', async () => {
		const error = new Error('processFile failure');
		processFileMock.mockRejectedValue(error);
       try{
		   await executeTest(Buffer.from('test zip buffer'));
	   }catch(error){
		   // @ts-ignore
		   expect(showError).not.toHaveBeenCalledWith(`${error.message}`);
	   }

	});
});
