/**
* Copyright Super iPaaS Integration LLC, an IBM Company 2024
*/
import { deployAction } from './deploy-action.js';
import { prepareGatewayJson, prepareArchiveBuffer, executeDeployment } from '../deployers/project/projects-deployer.js';
import { buildAssets, buildProjects } from './helpers/build-action-helper.js';
import { processDeployment } from '@apic/studio-deploy';
import { showInfo, showWarning } from '../helpers/common/message-helper.js';
import { processProjectBuild } from '@apic/studio-build';
import { IGNORE_PROJECT_ARG } from '../constants/message-constants.js';

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

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`,
	}));
});
// Mock the imported functions
jest.mock('../deployers/project/projects-deployer.js');
jest.mock('./helpers/build-action-helper.js');

jest.mock('../helpers/common/message-helper.js', () => ({
	showInfo: jest.fn() as jest.MockedFunction<typeof showInfo>,
	showWarning: jest.fn(), 
	showError: jest.fn()
}));

jest.mock('./test-action.js', () => ({
    setupDebugManager: jest.fn(),
}));

describe('Deploy Action Test Suite', () => {
	const mockGatewayJson = { key: 'value' };
	const mockArchiveBuffer = Buffer.from('mockArchiveBuffer');
	const mockZipBuffer = Buffer.from('mockZipBuffer');
	const mockOptions = {
		localDir: '/mock/root/dir',
		all: false,
		archive: '',
		target: 'mockTarget',
		username: 'mockUser',
		password: 'xyz',
		authToken: '',
		overwrite: true,
		project: 'mockProject',
		names: 'mockNames',
		debug: true
	};

	beforeEach(() => {
		jest.clearAllMocks();
		(prepareGatewayJson as jest.Mock).mockReturnValue(mockGatewayJson);
		(prepareArchiveBuffer as jest.Mock).mockReturnValue(mockArchiveBuffer);
		(buildAssets as jest.Mock).mockResolvedValue(mockZipBuffer);
		(buildProjects as jest.Mock).mockResolvedValue(mockZipBuffer);
	});

	test('should prepare gatewayJson and deploy using an archive', async () => {
		const optionsWithArchive = { ...mockOptions, archive: 'mockArchive' };

		await deployAction('mockProjects', optionsWithArchive);

		expect(prepareGatewayJson).toHaveBeenCalledWith('mockTarget', 'mockUser', 'xyz', true,false);
		expect(prepareArchiveBuffer).toHaveBeenCalledWith('mockArchive');
		expect(executeDeployment).toHaveBeenCalledWith(mockGatewayJson, mockArchiveBuffer);
		expect(buildAssets).not.toHaveBeenCalled();
		expect(buildProjects).not.toHaveBeenCalled();
	});

	test('should prepare gatewayJson and deploy using buildAssets when names are provided', async () => {
		const optionsWithNames = { ...mockOptions, archive: '', names: 'mockNames' };

		await deployAction('mockProjects', optionsWithNames);

		expect(prepareGatewayJson).toHaveBeenCalledWith('mockTarget', 'mockUser', 'xyz', true,false);
		expect(buildAssets).toHaveBeenCalledWith('mockNames', '/mock/root/dir', 'mockProjects');
		expect(executeDeployment).toHaveBeenCalledWith(mockGatewayJson, mockZipBuffer);
		expect(prepareArchiveBuffer).not.toHaveBeenCalled();
		expect(buildProjects).not.toHaveBeenCalled();
	});

	test('should prepare gatewayJson and deploy using buildProjects when all is true', async () => {
		const optionsWithAll = { ...mockOptions, archive: '', names: '', all: true };

		await deployAction('mockProjects', optionsWithAll);

		expect(prepareGatewayJson).toHaveBeenCalledWith('mockTarget', 'mockUser', 'xyz', true,false);
		expect(buildProjects).toHaveBeenCalledWith(true, '/mock/root/dir', 'mockProjects');
		expect(executeDeployment).toHaveBeenCalledWith(mockGatewayJson, mockZipBuffer);
		expect(prepareArchiveBuffer).not.toHaveBeenCalled();
		expect(buildAssets).not.toHaveBeenCalled();
		expect(showWarning).toHaveBeenCalledWith(IGNORE_PROJECT_ARG);

	});

	test('should throw an error if executeDeployment fails', async () => {
		const mockError = new Error('Deployment failed');
		(executeDeployment as jest.Mock).mockImplementation(() => { throw mockError; });

		await expect(deployAction('mockProjects', mockOptions)).rejects.toThrow('Deployment failed');

		expect(prepareGatewayJson).toHaveBeenCalledWith('mockTarget', 'mockUser', 'xyz', true,false);
		expect(executeDeployment).toHaveBeenCalled();
	});
});
