/**
* Copyright Super iPaaS Integration LLC, an IBM Company 2024
*/
import { processDeployment, validateGateways } from '../../src/index.js';
import fs from 'fs';
import path from 'path';
import * as GatewayService from '../../src/service/gateway-service.js';
import { LogWrapper } from '../../src/service/log-wrapper.js';
import { AppConstants } from '../../src/constants/app-constants.js';
jest.mock('@apic/studio-logger', () => ({
	LoggerConfig: {
		isLoggerEnabled: jest.fn(),
	},
}));
jest.mock('../../src/service/log-wrapper.ts');

describe('processDeployment', () => {
	beforeEach(() => {
		jest.clearAllMocks();
	});

	it('should return response on deployment', async () => {
		const gatewaysJson = {
			'gateways': [
				{
					'gatewayURL': 'http://example.com',
					'gatewayUser': 'user',
					'gatewaySecret': '123456',
					'is_mcsp_enabled': false
				}
			],
			'overwrite': 'apis,alias',
			'skip': 'policies'
		};
		const zipFilePath = path.resolve(__dirname, '../assets/gateway-asset.zip');
		const zipBuffer = fs.readFileSync(zipFilePath);
		const mock = jest.spyOn(GatewayService, 'sendToGateway');
		mock.mockImplementation(() => {
			return Promise.resolve({
				error: false,
				statusCode: 200,
				data: 'success'
			});
		});
		const result = await processDeployment(gatewaysJson, zipBuffer);
		expect(result).toStrictEqual([{
			error: false,
			statusCode: 200,
			data: 'success'
		}]);
		expect(result[0].error).toBeFalsy();

		expect(LogWrapper.logInfo).toHaveBeenCalledWith('0105', '1');
		expect(LogWrapper.logDebug).toHaveBeenCalledWith('0106', 'http://example.com');
		expect(LogWrapper.logDebug).toHaveBeenCalledWith('0003', 'Gateway Response: success');
		expect(LogWrapper.logInfo).toHaveBeenCalledWith('0003', 'Deployment process completed.');

		expect(LogWrapper.logError).not.toHaveBeenCalled();
		expect(LogWrapper.logWarn).not.toHaveBeenCalled();
	});

	it('should return response on multi deployment', async () => {
		const gatewaysJson = {
			'gateways': [
				{
					'gatewayURL': 'http://example.com',
					'gatewayUser': 'user',
					'gatewaySecret': '123456',
					'is_mcsp_enabled': false
				},
				{
					'gatewayURL': 'http://example2.com',
					'gatewayUser': 'user2',
					'gatewaySecret': '123456',
					'is_mcsp_enabled': false
				}
			],
			'overwrite': 'apis,alias',
			'skip': 'policies'
		};
		const zipFilePath = path.resolve(__dirname, '../assets/gateway-asset.zip');
		const zipBuffer = fs.readFileSync(zipFilePath);
		const mock = jest.spyOn(GatewayService, 'sendToGateway');
		mock.mockImplementation(() => {
			return Promise.resolve({
				error: false,
				statusCode: 200,
				data: 'success'
			});
		});
		const result = await processDeployment(gatewaysJson, zipBuffer);
		expect(result).toStrictEqual([{
			error: false,
			statusCode: 200,
			data: 'success'
		}, {
			error: false,
			statusCode: 200,
			data: 'success'
		}]);
		expect(result[0].error).toBeFalsy();

		expect(LogWrapper.logInfo).toHaveBeenCalledWith('0105', '2');
		expect(LogWrapper.logDebug).toHaveBeenCalledWith('0106', 'http://example.com');
		expect(LogWrapper.logDebug).toHaveBeenCalledWith('0106', 'http://example2.com');
		expect(LogWrapper.logDebug).toHaveBeenCalledWith('0003', 'Gateway Response: success');
		expect(LogWrapper.logInfo).toHaveBeenCalledWith('0003', 'Deployment process completed.');

		expect(LogWrapper.logError).not.toHaveBeenCalled();
		expect(LogWrapper.logWarn).not.toHaveBeenCalled();
	});

	it('should return warning on deployment with no gateways', async () => {
		const gatewaysJson = {
			'gateways': [
			],
			'overwrite': 'apis,alias',
			'skip': 'policies'
		};
		const zipFilePath = path.resolve(__dirname, '../assets/gateway-asset.zip');
		const zipBuffer = fs.readFileSync(zipFilePath);

		const result = await processDeployment(gatewaysJson, zipBuffer);
		expect(result).toStrictEqual([]);

		expect(LogWrapper.logWarn).toHaveBeenCalledWith('0003', 'No gateways to deploy.');
		expect(LogWrapper.logInfo).toHaveBeenCalledWith('0003', 'Deployment process completed.');

		expect(LogWrapper.logError).not.toHaveBeenCalled();
		expect(LogWrapper.logDebug).not.toHaveBeenCalled();
	});

	it('should return error response on deployment error', async () => {
		const gatewaysJson = {
			'gateways': [
				{
					'gatewayURL': 'http://example.com',
					'gatewayUser': 'user',
					'gatewaySecret': '123456',
					'is_mcsp_enabled': false
				}
			],
			'overwrite': 'apis,alias',
			'skip': 'policies'
		};
		const zipFilePath = path.resolve(__dirname, '../assets/gateway-asset.zip');
		const zipBuffer = fs.readFileSync(zipFilePath);
		const mock = jest.spyOn(GatewayService, 'sendToGateway');
		mock.mockImplementation(() => {
			throw new Error('Gateway not found');
		});
		const result = await processDeployment(gatewaysJson, zipBuffer);
		expect(result).toStrictEqual([{ error: true, message: 'Error sending to http://example.com: Gateway not found' }]);
		expect(result[0].error).toBeTruthy();

		expect(LogWrapper.logInfo).toHaveBeenCalledWith('0105', '1');
		expect(LogWrapper.logDebug).toHaveBeenCalledWith('0106', 'http://example.com');
		expect(LogWrapper.logError).toHaveBeenCalledWith('0013', 'deploying to', 'Error sending to http://example.com: Gateway not found');
		expect(LogWrapper.logInfo).toHaveBeenCalledWith('0003', 'Deployment process completed.');

		expect(LogWrapper.logWarn).not.toHaveBeenCalled();
	});
	it('should return error response on deployment error due to promise rejection', async () => {
		const gatewaysJson = {
			'gateways': [
				{
					'gatewayURL': 'http://example.com',
					'gatewayUser': 'user',
					'gatewaySecret': '123456',
					'is_mcsp_enabled': false
				}
			],
			'overwrite': 'apis,alias',
			'skip': 'policies'
		};
		const zipFilePath = path.resolve(__dirname, '../assets/gateway-asset.zip');
		const zipBuffer = fs.readFileSync(zipFilePath);
		const mock = jest.spyOn(GatewayService, 'sendToGateway');
		mock.mockImplementation(() => {
			return Promise.reject({
				error: true,
				statusCode: 404,
				data: 'Gateway not found'
			});
		});
		const result = await processDeployment(gatewaysJson, zipBuffer);
		expect(result).toStrictEqual([{ error: true, message: 'Unknown error sending to http://example.com' }]);
		expect(result[0].error).toBeTruthy();

		expect(LogWrapper.logInfo).toHaveBeenCalledWith('0105', '1');
		expect(LogWrapper.logDebug).toHaveBeenCalledWith('0106', 'http://example.com');
		expect(LogWrapper.logError).toHaveBeenCalledWith('0003', 'Unknown error sending to http://example.com');
		expect(LogWrapper.logInfo).toHaveBeenCalledWith('0003', 'Deployment process completed.');

		expect(LogWrapper.logWarn).not.toHaveBeenCalled();
	});

});



jest.mock('../../src/service/gateway-service.js');
const mockedValidationManager = GatewayService.validationManager as jest.MockedFunction<typeof GatewayService.validationManager>;

describe('validateGateways', () => {
	const url = 'https://example.com';
	const authHeader = 'Bearer token';

	beforeEach(() => {
		jest.clearAllMocks();
	});

	it('should return the result from validationManager on success', async () => {
		mockedValidationManager.mockResolvedValue({ data: 'OK', status: 200 });

		await expect(validateGateways(url, authHeader)).resolves.toEqual({ data: 'OK', status: 200 });
		expect(mockedValidationManager).toHaveBeenCalledWith(`${url}${AppConstants.GATEWAY_VALIDATION_URL}`, authHeader);
	});

	it('should throw a 400 error if URL is missing', async () => {
		await expect(validateGateways('', authHeader)).rejects.toThrow(
			JSON.stringify({ message: { data: 'Invalid parameters: URL and Authorization Header are required.', status: 400 } })
		);
	});

	it('should throw a 400 error if authHeader is missing', async () => {
		await expect(validateGateways(url, '')).rejects.toThrow(
			JSON.stringify({ message: { data: 'Invalid parameters: URL and Authorization Header are required.', status: 400 } })
		);
	});

	it('should propagate errors thrown by validationManager', async () => {
		const error = new Error('Validation failed');
		mockedValidationManager.mockRejectedValue(error);

		await expect(validateGateways(url, authHeader)).rejects.toThrow('Validation failed');
	});
});
