/**
* Copyright Super iPaaS Integration LLC, an IBM Company 2024
*/
import newman from 'newman';
import { ExtendedNewmanRunExecution } from '../models/interface.js';
import { LogWrapper } from '../service/log-wrapper.js';

export class NewmanRunner {
	private readonly collection: { info: { name: string; version: string; schema: string; }; item: never[]; };

	constructor(collection: { info: { name: string; version: string; schema: string; }; item: never[]; }) {
		this.collection = collection;
	}

	public run() {
		return new Promise((resolve, reject) => {
			LogWrapper.logInfo('0215', `${this.collection.info.name}`);
			newman.run({ collection: this.collection }, (err, summary) => {
				if (err) {
					LogWrapper.logError('0013', 'running tests', `${err.message}`);
					reject(new Error('Error running tests'));
					return;
				}
				try {
					LogWrapper.logDebug('0003', 'Newman run completed. Processing results.');
					const results = this.getExecutionResults(summary.run.executions);
					const filteredSummary = this.createFilteredSummary(summary, results);
					LogWrapper.logInfo('0216', `${this.collection.info.name}`);
					resolve(filteredSummary);
					return;
				} catch (error) {
					LogWrapper.logError('0013', 'processing test results', (error as Error).message);
					reject(new Error('Error processing test results'));
					return;
				}
			});
		});
	}

	private getExecutionResults(executions: ExtendedNewmanRunExecution[]) {
		const getResponse=(execution: ExtendedNewmanRunExecution) =>{
			if (execution.response?.stream) {
				return execution.response?.stream.toString();
			} else if (execution.response?.body) {
				return  execution.response?.body;
			} else {
				return 'Response unavailable';
			}
		};
		const formatExecution = (execution: ExtendedNewmanRunExecution) => {
			try {
				return {
					id: execution.id,
					name: execution.item.name,
					url: execution.request.url.toString(),
					method: execution.request.method,
					header: execution.request.headers,
					time: execution.response?.responseTime || 0,
					responseCode: {
						code: execution.response?.code || 408,
						name: execution.response?.status || 'Request Timed out',
						time: execution.response?.responseTime || 0,
						size: execution.response?.responseSize || 0
					},
					response: getResponse(execution),
					responseHeaders: execution.response?.headers || null,
					allTests: execution.assertions.map(assertion => ({
						[assertion.assertion]: assertion.error ? {
							status: false,
							error: assertion.error
						} : { status: true }
					}))
				};
			} catch (error) {
				LogWrapper.logError('0013', `formatting execution with id ${execution.id}`, (error as Error).message);
				return null;
			}
		};

		try {
			LogWrapper.logDebug('0003', 'Formatting execution results.');
			return executions.map(formatExecution).filter(result => result !== null);
		} catch (e) {
			LogWrapper.logError('0013', 'processing executions', (e as Error).message);
			return [];
		}
	}

	// @ts-ignore
	private createFilteredSummary(summary: newman.NewmanRunSummary, results) {
		LogWrapper.logDebug('0003', 'Creating filtered summary from execution results.');
		return {
			id: summary.collection.id,
			name: summary.collection.name,
			timestamp: summary.run.timings.completed,
			// @ts-ignore
			totalPass: summary.run.stats.assertions.total - summary.run.stats.assertions.failed,
			status: summary.run.failures.length === 0 ? 'finished' : 'failed',
			startedAt: summary.run.timings.started,
			totalFail: summary.run.stats.assertions.failed,
			totalTime: (summary.run.timings.completed && summary.run.timings.started)
				? summary.run.timings.completed - summary.run.timings.started
				: undefined,
			results: results
		};
	}
}
