/**
* Copyright Super iPaaS Integration LLC, an IBM Company 2024
*/
import { prepareGatewayJson, prepareArchiveBuffer, executeDeployment } from './projects-deployer.js';
import { processDeployment } from '@apic/studio-deploy';
import { showError, showInfo, showSuccess } from '../../helpers/common/message-helper.js';
import { readFileAsBuffer } from '../../helpers/common/fs-helper.js';
import {
	APIENDPOINTS,
	DEPLOY_STARTED,
	DEPLOYMENT_FAILURE,
	LINE,
} from '../../constants/message-constants.js';

let mockExit: jest.SpyInstance;
jest.mock('@apic/studio-deploy', () => ({
	processDeployment: jest.fn() as jest.MockedFunction<typeof processDeployment>,
}));

jest.mock('../../helpers/common/message-helper.js', () => ({
	showError: jest.fn(),
	showInfo: jest.fn(),
	showSuccess: jest.fn()
}));

jest.mock('@apic/studio-build', () => ({
	processProjectBuild: jest.fn(),
}));



beforeEach(() => {
	// @ts-ignore
	mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {
	});
});

jest.mock('env-paths', () => {
	return jest.fn((name: string) => ({
		data: `/mock/path/${name}-data`,
		config: `/mock/path/${name}-config`,
		cache: `/mock/path/${name}-cache`,
		log: `/mock/path/${name}-log`,
		temp: `/mock/path/${name}-temp`,
	}));
});
jest.mock('../../helpers/common/fs-helper.js', () => ({
	readFileAsBuffer: jest.fn() as jest.MockedFunction<typeof readFileAsBuffer>,
}));
jest.mock('cli-table3', () => {
	return jest.fn().mockImplementation(() => ({
		push: jest.fn(),
		toString: jest.fn().mockReturnValue(
			'┌──────────┬─────────────────────┐\n' +
            '│ APIs     │ Gateway Endpoints   │\n' +
            '├──────────┼─────────────────────┤\n' +
            '│ Test API │ http://example.com  │\n' +
            '│          │ http://example2.com │\n' +
            '└──────────┴─────────────────────┘'
		)
	}));
});

describe('Projects deployer, Test suite', () => {
	beforeEach(() => {
		jest.clearAllMocks();
	});

	describe('prepareGatewayJson', () => {
		it('should return correct GatewaysJson', () => {
			const result = prepareGatewayJson('http://example.com', 'user', '', true,false);
			expect(result).toEqual({
				gateways: [{
					gatewayURL: 'http://example.com',
					gatewayUser: 'user',
					gatewaySecret: '',
					is_mcsp_enabled: false
				}],
				overwrite: 'all',
				skip: 'none',
			});
		});

		it('should handle skip and overwrite correctly when false', () => {
			const result = prepareGatewayJson('http://example.com', 'user', '', false,false);
			expect(result).toEqual({
				gateways: [{
					gatewayURL: 'http://example.com',
					gatewayUser: 'user',
					gatewaySecret: '',
					is_mcsp_enabled: false
				}],
				overwrite: 'none',
				skip: 'all',
			});
		});
		it('should handle non-URL strings for target', () => {
			const result = prepareGatewayJson('not-a-url', 'user', 'xyz', true,false);
			expect(result).toEqual({
			gateways: [
				{
				  gatewayURL: 'not-a-url',
				  gatewayUser: 'user',
				  gatewaySecret: 'xyz',
				  is_mcsp_enabled: false
				},
			  ],
			  overwrite: 'all',
			  skip: 'none',
			});
		  });
		  it('should handle special characters in username and password', () => {
			const result = prepareGatewayJson('http://example.com', 'user!@#$', 'xyz', true,false);
			expect(result).toEqual({
			  gateways: [
				{
				  gatewayURL: 'http://example.com',
				  gatewayUser: 'user!@#$',
				  gatewaySecret: 'xyz',
				  is_mcsp_enabled: false
				},
			  ],
			  overwrite: 'all',
			  skip: 'none',
			});
		  });
	});

	describe('prepareArchiveBuffer', () => {
		it('should call readFileAsBuffer with the correct path', () => {
			const mockBuffer = Buffer.from('test');
			(readFileAsBuffer as jest.Mock).mockReturnValue(mockBuffer);

			const result = prepareArchiveBuffer('path/to/archive.zip');
			expect(readFileAsBuffer).toHaveBeenCalledWith('path/to/archive.zip');
			expect(result).toBe(mockBuffer);
		});
		it('should handle large file buffer', () => {
			const largeBuffer = Buffer.alloc(1024 * 1024 * 100); // 100MB
			(readFileAsBuffer as jest.Mock).mockReturnValue(largeBuffer);
		
			const result = prepareArchiveBuffer('/path/to/large-file');
			expect(result.byteLength).toBe(1024 * 1024 * 100);
		  });
		
		  it('should handle files with special characters in path', () => {
			const mockBuffer = Buffer.from('special content');
			(readFileAsBuffer as jest.Mock).mockReturnValue(mockBuffer);
		
			const result = prepareArchiveBuffer('/path/to/file-with-特殊字符');
			expect(result).toBe(mockBuffer);
		  });
		it('should handle non-existent file gracefully', () => {
			(readFileAsBuffer as jest.Mock).mockImplementation(() => {
			throw new Error('File not found');
			});
		
			expect(() => prepareArchiveBuffer('/path/to/non-existent-file')).toThrow('File not found');
		});
	});

	describe('executeDeployment', () => {
		const mockConsoleLog = jest.spyOn(console, 'log').mockImplementation(() => {});
	
		beforeEach(() => {
			jest.clearAllMocks();
		});
	
		it('should handle successful deployments without errors', async () => {
			const gatewayJson = { gateways: [], overwrite: 'ALL', skip: 'NONE' };
			const fileBuffer = Buffer.from('mock data');
			const mockResponses = [
				{ error: false, data: { StudioResult: [{ API: { name: 'Test API', gatewayEndpoints: ['http://example.com', 'http://example2.com'] } }] } }
			];
	
			(processDeployment as jest.Mock).mockResolvedValue(mockResponses);
	
			await executeDeployment(gatewayJson, fileBuffer);
	
			expect(showInfo).toHaveBeenCalledWith(LINE);
			expect(showInfo).toHaveBeenCalledWith(DEPLOY_STARTED);
			expect(showSuccess).toHaveBeenCalledWith(APIENDPOINTS);
			expect(mockConsoleLog).toHaveBeenCalledWith(
				'┌──────────┬─────────────────────┐\n' +
				'│ APIs     │ Gateway Endpoints   │\n' +
				'├──────────┼─────────────────────┤\n' +
				'│ Test API │ http://example.com  │\n' +
				'│          │ http://example2.com │\n' +
				'└──────────┴─────────────────────┘'
			);
		});
	
		it('should handle deployment errors and log them correctly', async () => {
			const gatewayJson = { gateways: [], overwrite: 'ALL', skip: 'NONE' };
			const fileBuffer = Buffer.from('mock data');
			const mockResponses = [{ error: true, message: 'Deployment failed' }];
	
			(processDeployment as jest.Mock).mockResolvedValue(mockResponses);
	
			await executeDeployment(gatewayJson, fileBuffer);
	
			expect(showError).toHaveBeenCalledWith(DEPLOYMENT_FAILURE);
			expect(showError).toHaveBeenCalledWith('Deployment failed');
		});
	
		it('should handle responses with successful deployments and log API endpoints', async () => {
			const gatewayJson = { gateways: [], overwrite: 'ALL', skip: 'NONE' };
			const fileBuffer = Buffer.from('mock data');
			const mockResponses = [
				{ error: false, data: { StudioResult: [{ API: { name: 'Test API', gatewayEndpoints: ['http://example.com', 'http://example2.com'], kind: 'API', namespace: 'test', version: '1.0', assetName: 'testAPI' } }] } }
			];
		
			(processDeployment as jest.Mock).mockResolvedValue(mockResponses);
		
			await executeDeployment(gatewayJson, fileBuffer);
		
			expect(showInfo).toHaveBeenCalledWith(LINE);
			expect(showInfo).toHaveBeenCalledWith(DEPLOY_STARTED);
			expect(showSuccess).toHaveBeenCalledWith(APIENDPOINTS);
			expect(mockConsoleLog).toHaveBeenCalledWith(
				'┌──────────┬─────────────────────┐\n' +
				'│ APIs     │ Gateway Endpoints   │\n' +
				'├──────────┼─────────────────────┤\n' +
				'│ Test API │ http://example.com  │\n' +
				'│          │ http://example2.com │\n' +
				'└──────────┴─────────────────────┘'
			);
		});
		it('should handle partial success in deployment', async () => {
			const mockGatewayJson = { gateways: [], overwrite: '', skip: '' };
            const mockBuffer = Buffer.from('test buffer');
			const partialSuccessResponse = [{
			data: { StudioResult: [{ API: { status: 'Success', name: 'API1', namespace: 'ns', version: 'v1', assetName: 'asset1', gatewayEndpoints: ['endpoint1'] } }, { API: { status: 'Failure', name: 'API2', namespace: 'ns2', version: 'v2', assetName: 'asset2', gatewayEndpoints: ['endpoint2'] } }] }
			}];
			(processDeployment as jest.Mock).mockResolvedValue(partialSuccessResponse);
			
			await executeDeployment(mockGatewayJson, mockBuffer);
		
			expect(showSuccess).toHaveBeenCalledWith('\nGateway endpoints of the APIs in the project');
		});
	});
});