/**
* Copyright Super iPaaS Integration LLC, an IBM Company 2024
*/
import axios from 'axios';
import FormData from 'form-data';
import { sendToGateway } from '../../src/service/gateway-service.js';
import { GatewaysJson } from '../../src/index.js';
import { AppConstants } from '../../src/constants/app-constants.js';
import { LogWrapper } from '../../src/service/log-wrapper.js';
import { validationManager } from '../../src/service/gateway-service.js'
jest.mock('@apic/studio-logger', () => ({
	LoggerConfig: {
		isLoggerEnabled: jest.fn(),
	},
}));

jest.mock('axios');
jest.mock('../../src/service/log-wrapper.ts');

describe('sendToGateway', () => {
	const gatewayURL = 'http://gateway.com';
	const gatewayUser = 'user';
	const gatewaySecret = '';
	const zipBuffer = Buffer.from('zipped content');
	const gatewaysJsonContent: GatewaysJson = {
		gateways: [
			{
				gatewayURL: 'http://gateway1.com',
				gatewayUser: 'user1',
				gatewaySecret: '',
				is_mcsp_enabled: true
			},
		],
		overwrite: 'true',
		skip: 'false',
	};

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

	it('should send data to the gateway and return response data on success', async () => {
		const mockResponse = { data: { success: true } };
		(axios.post as jest.Mock).mockResolvedValue(mockResponse);

		const result = await sendToGateway(gatewayURL, gatewayUser, gatewaySecret,false, zipBuffer, gatewaysJsonContent);

		expect(axios.post).toHaveBeenCalledWith(
			gatewayURL + AppConstants.DEPLOY_GATEWAY_URL,
			expect.any(FormData),
			expect.objectContaining({
				headers: expect.objectContaining({
					'Authorization': expect.stringContaining('Basic '),
				}),
			})
		);
		expect(result).toEqual({
			data: { success: true },
			error: false,
			statusCode: undefined,
		});
		expect(LogWrapper.logDebug).toHaveBeenCalledWith('0108', 'http://gateway.com');
		expect(LogWrapper.logDebug).toHaveBeenCalledWith('0010', JSON.stringify(mockResponse.data));
	});
	it('should handle HTTP errors gracefully', async () => {
		const mockError = {
			message: 'Request failed',
			response: {
				status: 500,
				data: { error: 'Internal Server Error' },
			},
		};
		(axios.post as jest.Mock).mockRejectedValue(mockError);

		const result = await sendToGateway(gatewayURL, gatewayUser, gatewaySecret,false, zipBuffer, gatewaysJsonContent);

		expect(result).toEqual({
			error: true,
			statusCode: 500,
			data: { error: 'Internal Server Error' },
		});
		expect(LogWrapper.logError).toHaveBeenCalledWith(
			'0009',
			'Deployment',
			`Error sending to ${gatewayURL}: Request failed`
		);
		expect(LogWrapper.logDebug).toHaveBeenCalledWith('0108', 'http://gateway.com');
	});

	it('should handle network errors gracefully', async () => {
		const mockError = {
			message: 'Network Error',
		};
		(axios.post as jest.Mock).mockRejectedValue(mockError);

		const result = await sendToGateway(gatewayURL, gatewayUser, gatewaySecret,false, zipBuffer, gatewaysJsonContent);

		expect(result).toEqual({
			error: true,
			statusCode: 404,
			data: null,
		});
		expect(LogWrapper.logError).toHaveBeenCalledWith(
			'0009',
			'Deployment',
			`Error sending to ${gatewayURL}: Network Error`
		);
		expect(LogWrapper.logDebug).toHaveBeenCalledWith('0108', 'http://gateway.com');
	});

	it('should create FormData with the correct content', async () => {
		const formData = new FormData();
		formData.append('file', zipBuffer, 'gatewayInstance.zip');
		formData.append('overwrite', gatewaysJsonContent.overwrite);

		const appendSpy = jest.spyOn(FormData.prototype, 'append');

		await sendToGateway(gatewayURL, gatewayUser, gatewaySecret, false, zipBuffer, gatewaysJsonContent);

		expect(appendSpy).toHaveBeenCalledWith('file', zipBuffer, 'gatewayInstance.zip');
		expect(appendSpy).toHaveBeenCalledWith('overwrite', gatewaysJsonContent.overwrite);
	});
});


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

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

	it('should return { data: "OK", status: 200 } for a successful request', async () => {
		(axios.get as jest.Mock).mockResolvedValue({ status: 200, data: 'Success' });
		await expect(validationManager(url, authorizationHeader)).resolves.toEqual({ data: 'OK', status: 200 });
	});

	it('should throw an error for a 401 Unauthorized response', async () => {
		(axios.get as jest.Mock).mockRejectedValue({ response: { status: 401, data: 'Unauthorized' } });
		await expect(validationManager(url, authorizationHeader)).rejects.toThrow(
			JSON.stringify({ message: { data: 'The user name or password did not match.', status: 401 } })
		);
	});

	it('should throw an error for a 502 Bad Gateway response', async () => {
		(axios.get as jest.Mock).mockRejectedValue({ response: { status: 502, data: 'Bad Gateway' } });
		await expect(validationManager(url, authorizationHeader)).rejects.toThrow(
			JSON.stringify({ message: { data: 'Bad Gateway', status: 502 } })
		);
	});

	it('should throw an error for a 404 Not Found response', async () => {
		(axios.get as jest.Mock).mockRejectedValue({ response: { status: 404, data: 'Not Found' } });
		await expect(validationManager(url, authorizationHeader)).rejects.toThrow(
			JSON.stringify({ message: { data: 'Gateway not found', status: 404 } })
		);
	});

	it('should throw an error for a timeout', async () => {
		(axios.get as jest.Mock).mockRejectedValue({ code: 'ECONNABORTED' });
		await expect(validationManager(url, authorizationHeader)).rejects.toThrow(
			JSON.stringify({ message: { data: 'Gateway not found', status: 404 } })
		);
	});

	it('should throw an error for an unknown error', async () => {
		(axios.get as jest.Mock).mockRejectedValue(new Error('Unknown error'));
		await expect(validationManager(url, authorizationHeader)).rejects.toThrow(
			JSON.stringify({ message: { data: 'Something went wrong while validating the gateway.', status: 500 } })
		);
	});
	it('should throw an error for an unexpected status code', async () => {
		(axios.get as jest.Mock).mockResolvedValue({ status: 418, data: 'I’m a teapot' });
		await expect(validationManager(url, authorizationHeader)).rejects.toThrow(
			JSON.stringify({ message: { data: "Something went wrong while validating the gateway.", status: 500 } })
		);
	});
});

