import { TestManager } from '@apic/studio-test';
import { showSuccess, showError, showInfo} from '../../helpers/common/message-helper.js';
import Table from 'cli-table3';
import {TestResult} from '../../model/studio/test-response-model.js';
import {
	CREATE_TEST_TABLE, CREATE_TEST_TABLE_SUCCESS, EMPTY_RESULT, ERROR_GENERATE_TEST_RESULTS_FILE,
	ERROR_IN_EXECUTING_TEST,
	ERROR_PREPARE_TEST_RESULTS,
	EXECUTING_TEST,
	EXECUTING_TESTS_SUCCESS, FAILED, FAILED_TESTS, INDIVIDUAL_TEST_RESULT_HEADINGS, INDIVIDUAL_TEST_SUMMARY_HEADINGS,
	LINE, OVERALL_TEST_SUMMARY, OVERALL_TEST_SUMMARY_HEADINGS, PASSED,
	PREPARE_TEST_RESULT,
	PREPARE_TEST_RESULT_SUCCESS,
	PREPARE_TESTS_RESULT,
	PREPARE_TESTS_RESULT_SUCCESS,
	TESTING
} from '../../constants/message-constants.js';
import { DebugManager } from '../../debug/debug-manager.js';
import {
	generateFileInRootDir
} from '../../helpers/common/fs-helper.js';
import {OverAllTestSummary} from '../../model/overall-summary.js';
import {TestCaseFailureError} from '../../Errors/test-case-failure-error.js';


export const executeTest = async (zipBuffer: Buffer) => {
		const testManager = new TestManager();
		if(DebugManager.getInstance().isDebugEnabled()){
			showInfo(EXECUTING_TEST);
		}
		const result = await testManager.processFile(zipBuffer);
		if (result === null) {
			showError(ERROR_IN_EXECUTING_TEST);
			throw new Error(ERROR_IN_EXECUTING_TEST);
		}
		const testResults = result as TestResult[];
		if(testResults && testResults.length>0){
			const overAllSummary: OverAllTestSummary | undefined = calculateOverAllTestSummary(testResults);
			showInfo(LINE);
			showInfo(TESTING);
			showInfo(LINE);
			showSuccess(EXECUTING_TESTS_SUCCESS);
			await prepareTestResults(testResults);
			if(overAllSummary ){
				await writeTestResultsToFile(overAllSummary,testResults);
				if( overAllSummary.overAllStatus===FAILED){
					throw new TestCaseFailureError(FAILED_TESTS, 500);
				}
			}
		}else{
			showError(EMPTY_RESULT);
		}
};

const formatTestResult = (testResult: TestResult) => {
	const resultTable = createHeadingForTable(INDIVIDUAL_TEST_RESULT_HEADINGS);
	resultTable.push([
		testResult.name,
		testResult.totalPass,
		testResult.totalFail,
		testResult.status
	]);
	console.log(resultTable.toString());
};

function createHeadingForTable(headings: string[]) {
	return new Table({
		head: headings,
		style: {
			head: ['blue'],
			border: ['yellow'],
		},
	});
}

const createResultTable = (testResult: TestResult) => {
	if(DebugManager.getInstance().isDebugEnabled()){
		showInfo(CREATE_TEST_TABLE);
	}
	const resultTable = createHeadingForTable(INDIVIDUAL_TEST_SUMMARY_HEADINGS);

	testResult.results.forEach(result => {
		result.allTests.forEach(testGroup => {
			Object.entries(testGroup).forEach(([testName, testDetails]) => {
				resultTable.push([
					result.name,
					testName,
					testDetails.status ? PASSED : FAILED,
					testDetails.status ? '' : testDetails.error?.message || 'No error message'
				]);
			});
		});
	});
	if(DebugManager.getInstance().isDebugEnabled()){
		showInfo(CREATE_TEST_TABLE_SUCCESS);
	}

	return resultTable;
};


function calculateOverAllTestSummary(testResult: TestResult[]): OverAllTestSummary | undefined {
	if(testResult.length<1) {
		return undefined ;
	}
	const totalTestSuite = testResult.length;
	const totalTests = testResult.reduce((acc, res) => {
		return acc + res.results.reduce((innerAcc, result) => innerAcc + result.allTests.length, 0);
	}, 0);
	let overAllPassedTests = 0;
	let overAllFailedTests = 0;
	let overAllStatus = '';
	testResult.forEach(result => {
		overAllPassedTests += result.totalPass;
		overAllFailedTests += result.totalFail;
		overAllStatus = overAllFailedTests > 1 ? FAILED : PASSED;
	});
	return {totalTestSuite, totalTests, overAllPassedTests, overAllFailedTests, overAllStatus} as OverAllTestSummary;
}

function createOverAllTestSummary(testResult: TestResult[]) {

	const resultTable=createHeadingForTable(OVERALL_TEST_SUMMARY_HEADINGS);
	const testSummary = calculateOverAllTestSummary(testResult);
	if(testSummary){
		resultTable.push([testSummary.totalTestSuite,testSummary.totalTests,testSummary.overAllPassedTests,testSummary.overAllFailedTests,testSummary.overAllStatus]);
		return resultTable;
	}
	return undefined;

}

function printOverAllTestSummaryText() {
	showInfo(LINE);
	showInfo(OVERALL_TEST_SUMMARY);
	showInfo(LINE);
}

function generateOverAllSummary(results: TestResult[]) {
	if(results && results.length<=1) {
		return undefined;
	}
	printOverAllTestSummaryText();
	return createOverAllTestSummary(results);
}

const prepareTestResults = async (results: TestResult[]) => {
	try {
		if(DebugManager.getInstance().isDebugEnabled()){
			showInfo(PREPARE_TESTS_RESULT);
		}
		results.forEach(testResult => {
			if(DebugManager.getInstance().isDebugEnabled()){
				showInfo(JSON.stringify(testResult, null, 2));
			}
			if(DebugManager.getInstance().isDebugEnabled()){
				showInfo(`${PREPARE_TEST_RESULT}${testResult.name}`);
			}
			formatTestResult(testResult);
			const resultTable = createResultTable(testResult);
			console.log(resultTable.toString());

			if(DebugManager.getInstance().isDebugEnabled()){
				showInfo(`${PREPARE_TEST_RESULT_SUCCESS}${testResult.name}`);
			}
		});
		const overAllResultTable = generateOverAllSummary(results);
		if(overAllResultTable){
			console.log(overAllResultTable.toString());
		}
		if(DebugManager.getInstance().isDebugEnabled()){
			showInfo(PREPARE_TESTS_RESULT_SUCCESS);
		}
	} catch (error) {
		showError(`${ERROR_PREPARE_TEST_RESULTS}: ${(error as Error).message}`);
	}
};

export function getTestErrorData(error: Error) {
	return {
		'message': error.message,
		'detailedMessage': error.stack
		}
	}

export const writeTestResultsToFile = async (overAllSummary: OverAllTestSummary, testResults: TestResult[]): Promise<void> => {
	if(testResults.length<1)
	{
		return;
	}
	try{
		const testSummary = {
				overAllSummary,
				testResults
			};
		await generateFileInRootDir(testSummary);
	}catch(error){
		showError(ERROR_GENERATE_TEST_RESULTS_FILE);
		throw new Error(ERROR_GENERATE_TEST_RESULTS_FILE);
	}

};

