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

const assetMap = new Map<string, string>();
assetMap.set(AssertConstants.equals_action, AssertConstants.equals_template);
assetMap.set(AssertConstants.not_equals_action, AssertConstants.not_equals_template);
assetMap.set(AssertConstants.h_equals_action, AssertConstants.h_equals_template);
assetMap.set(AssertConstants.h_not_equals_action, AssertConstants.h_not_equals_template);
assetMap.set(AssertConstants.x_equals_action, AssertConstants.x_equals_template);
assetMap.set(AssertConstants.x_not_equals_action, AssertConstants.x_not_equals_template);
assetMap.set(AssertConstants.have_property_action, AssertConstants.have_property_template);
assetMap.set(AssertConstants.not_have_property_action, AssertConstants.not_have_property_template);
assetMap.set(AssertConstants.h_have_property_action, AssertConstants.h_have_property_template);
assetMap.set(AssertConstants.h_not_have_property_action, AssertConstants.h_not_have_property_template);

assetMap.set(AssertConstants.x_have_property_action, AssertConstants.x_have_property_template);
assetMap.set(AssertConstants.x_not_have_property_action, AssertConstants.x_not_have_property_template);

assetMap.set(AssertConstants.lessThan_action, AssertConstants.lessThan_template);
assetMap.set(AssertConstants.greaterThan_action, AssertConstants.greaterThan_template);
assetMap.set(AssertConstants.validateSchema_action, AssertConstants.validateSchema_template);
assetMap.set(AssertConstants.inValidateSchema_action, AssertConstants.inValidateSchema_template);
assetMap.set(AssertConstants.not_equals_action, AssertConstants.not_equals_template);
assetMap.set(AssertConstants.lengthOf_action, AssertConstants.have_lengthOf_template);
assetMap.set(AssertConstants.include_action, AssertConstants.include_template);
assetMap.set(AssertConstants.common_template, AssertConstants.include_template);

/* eslint-disable @typescript-eslint/no-explicit-any */
export type AssertType = { name: string, key: string, value: any, action: string };
type ValidationMessage = { status: boolean, message: string };

export class AssertionsGenerator implements IAssertMapper {

	initializeCommonScriptLibrary(): string {
		LogWrapper.logDebug('0003', 'Initializing common script library.');
		return AssertConstants.common_template;
	}

	converttoAssertionStructure(assertObject: AssertType) {
		LogWrapper.logDebug('0003', `Converting assertion structure for action: ${assertObject.action}`);
		const validation = this.validateAssertionModel(assertObject);

		if (!validation.status) {
			LogWrapper.logError('0255', validation.message);
			//	throw InvalidAssertion()
		}

		const assertion = this.getAssertionModel(assertObject.name, assertObject.key, assertObject.value, assertObject.action);
		LogWrapper.logInfo('0003', `Generated assertion structure for action: ${assertObject.action}`);
		return assertion;
	}

	autoCorrectionValue(name: string, key: string, value: any, action: string) {
		let assertvalue;
		LogWrapper.logDebug('0003', `Auto-correcting value for key: ${key}, action: ${action}`);

		if (key.includes(AssertConstants.responseHeaderKey)) {
			LogWrapper.logDebug('0003', 'Detected response header key, modifying action.');
			key = key.replace(AssertConstants.responseHeaderKey + '.', '');
			action = 'h_' + action;
		} else if (key.includes(AssertConstants.responseXmlTypeKey)) {
			LogWrapper.logDebug('0003', 'Detected response XML key, modifying action.');
			key = key.replace(AssertConstants.responseXmlTypeKey + '.', '');
			action = 'x_' + action;
		}

		assertvalue = assetMap.get(action);
		if (assertvalue) {
			assertvalue = assertvalue.replace(AssertConstants.namePlaceHolder, name)
				.replace(AssertConstants.keyPlaceHolder, key);

			if (typeof value === 'string') {
				assertvalue = assertvalue.replace(AssertConstants.valuePlaceHolder, `${AssertConstants.singleQuote}${value}${AssertConstants.singleQuote}`);
			} else if (typeof value === 'object') {
				assertvalue = assertvalue.replace(AssertConstants.valuePlaceHolder, JSON.stringify(value));
			} else {
				assertvalue = assertvalue.replace(AssertConstants.valuePlaceHolder, value);
			}
		} else {
			LogWrapper.logWarn('0003', `No template found for action: ${action}`);
		}

		LogWrapper.logDebug('0003', `Auto-corrected value for key: ${key}, action: ${action}`);
		return assertvalue;
	}

	validateAssertionModel(assertObject: AssertType): ValidationMessage {
		LogWrapper.logDebug('0003', `Validating assertion model for action: ${assertObject.action}`);
		const validStatus: ValidationMessage = { status: true, message: '' };

		if (!assetMap.has(assertObject.action)) {
			validStatus.status = false;
			validStatus.message = `Invalid ${assertObject.action} not supported in studio.`;
			LogWrapper.logError('0004', validStatus.message);
		}

		LogWrapper.logDebug('0003', `Validation result for action: ${assertObject.action} - ${validStatus.status}`);
		return validStatus;
	}

	getAssertionModel(name: string, key: string, value: any, action: string) {
		LogWrapper.logDebug('0003', `Generating assertion model for ${action}`);
		const assertValue = this.autoCorrectionValue(name, key, value, action);

		if (assertValue === undefined) {
			LogWrapper.logWarn('0003', `Assertion model could not be generated for ${action}`);
			return '';
		}

		LogWrapper.logInfo('0003', `Successfully generated assertion model for ${action}`);
		return assertValue;
	}
}
