import { testAction } from './test-action.js'; // Adjust the import path
import { getGatewayJson, handleTestAssets, testAssetsForEndpoint, handleTestProjects, handleTestWarnings, writeArchive } from './helpers/test-action-helper.js';
import { TestOptionsModel } from '../model/studio/command-options/test-options-model.js';
import { DebugManager } from '../debug/debug-manager.js';
import { showError } from '../helpers/common/message-helper.js';
import { ENDPOINT_ARGUMENT_NOT_AVAILABLE, TEST_EXECUTION_FAILED } from '../constants/message-constants.js';
import {passwordPrompt} from '../prompts/input-prompt.js';
import { DEPENDENCY_DIRECTORY } from '../constants/app-constants.js';
import { parseEnvInput, updateEnvironmentAssetInZip } from '../helpers/apim/env-helper.js';
let mockExit: jest.SpyInstance;

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

jest.mock('@inquirer/prompts', () => ({
	password: jest.fn(),
}));

jest.mock('../helpers/apim/env-helper.js', () => ({
	parseEnvInput: jest.fn(),
	updateEnvironmentAssetInZip: jest.fn()
}));

jest.mock('./helpers/test-action-helper.js', () => ({
	getGatewayJson: jest.fn(),
	handleTestAssets: jest.fn(),
	handleTestProjects: jest.fn(),
	handleTestWarnings: jest.fn(),
	testAssetsForEndpoint:jest.fn(),
	writeArchive:jest.fn()
}));

jest.mock('../debug/debug-manager.js', () => ({
	DebugManager: {
		getInstance: jest.fn().mockReturnValue({
			setDebugEnabled: jest.fn(),
			isDebugEnabled:jest.fn()
			
		}),
	},
}));

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

jest.mock('@apic/studio-test', () => {
	return {
		TestManager: jest.fn().mockImplementation(() => {
			return {
				processFile: jest.fn(),
			};
		}),
	};
});

jest.mock('../prompts/input-prompt.js', () => ({
	passwordPrompt: jest.fn(),
}));

describe('testAction test suite', () => {
	const projects = 'projectA,projectB';
	const options = {
		localDir: 'mock/local/dir',
		names: 'projA,projB',
		all: false,
		debug: true,
	} as TestOptionsModel;

	const mockGatewayPassword = '';
	const mockGatewayJson = { key: 'value' };
	const mockTestZipBuffer = Buffer.from('mockTestZipBuffer');

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

	it('should call passwordPrompt, getGatewayJson, handleTestWarnings, handleTestAssets, and DebugManager.setDebugEnabled', async () => {
		const mockDebugManagerInstance = {
			setDebugEnabled: jest.fn(),
		};
		(DebugManager.getInstance as jest.Mock).mockReturnValue(mockDebugManagerInstance);

		(passwordPrompt as jest.Mock).mockResolvedValue(mockGatewayPassword);
		(getGatewayJson as jest.Mock).mockResolvedValue(mockGatewayJson);



		await testAction(projects, options);

		expect(passwordPrompt).toBeUndefined;
		expect(getGatewayJson).toHaveBeenCalledWith(options, mockGatewayPassword);
		expect(handleTestWarnings).toHaveBeenCalledWith(projects, options);
		expect(handleTestAssets).toHaveBeenCalledWith(options, projects, options.localDir, mockGatewayJson);
		expect(mockDebugManagerInstance.setDebugEnabled).toHaveBeenCalledWith(true);
	});

	it('should call handleTestProjects when options.names is empty and options.all is true', async () => {
		const optionsWithAll = { ...options, names: '', all: true };

		(passwordPrompt as jest.Mock).mockResolvedValue(mockGatewayPassword);
		(getGatewayJson as jest.Mock).mockResolvedValue(mockGatewayJson);

		await testAction(projects, optionsWithAll);

		expect(handleTestProjects).toHaveBeenCalledWith(optionsWithAll, projects, optionsWithAll.localDir, mockGatewayJson);
		expect(handleTestAssets).not.toHaveBeenCalled();
	});

	it('should handle errors and call showError', async () => {
		const errorMessage = 'mock error message';
		(passwordPrompt as jest.Mock).mockResolvedValue(mockGatewayPassword);
		(getGatewayJson as jest.Mock).mockResolvedValue(mockGatewayJson);
		(handleTestAssets as jest.Mock).mockRejectedValue(new Error(errorMessage));

		await testAction(projects, options);

		expect(showError).toHaveBeenCalledWith(`\n${TEST_EXECUTION_FAILED} ${errorMessage}`);
	});
	it('should update environment assets and write archive if options.env is provided', async () => {
		const envString = 'KEY1=value1,KEY2=value2';
		const options = {
			localDir: 'mock/local/dir',
			names: 'projA,projB',
			all: false,
			debug: true,
			env: envString
		} as TestOptionsModel;
	
		const mockGatewayPassword = '';
		const mockGatewayJson = { key: 'value' };
		const mockTestZipBuffer = Buffer.from('mockTestZipBuffer');
		const mockEnvMap = { KEY1: 'value1', KEY2: 'value2' };

		(passwordPrompt as jest.Mock).mockResolvedValue(mockGatewayPassword);
		(getGatewayJson as jest.Mock).mockResolvedValue(mockGatewayJson);
		(handleTestAssets as jest.Mock).mockResolvedValue({
			testZipBuffer: mockTestZipBuffer,
			buildZipBuffer: Buffer.from('mockBuildZipBuffer')
		});
		(parseEnvInput as jest.Mock).mockReturnValue(mockEnvMap);
		(updateEnvironmentAssetInZip as jest.Mock).mockResolvedValue(mockTestZipBuffer);
		(writeArchive as jest.Mock).mockResolvedValue(undefined);
	
		const mockDebugManagerInstance = {
			setDebugEnabled: jest.fn(),
			isDebugEnabled: jest.fn().mockReturnValue(true),
		};
		(DebugManager.getInstance as jest.Mock).mockReturnValue(mockDebugManagerInstance);
	
		const outputBuffers = {
			testZipBuffer: mockTestZipBuffer,
			buildZipBuffer: Buffer.from('mockBuildZipBuffer')
		};
	
		await testAction('projectA,projectB', options);
	
		expect(parseEnvInput).toHaveBeenCalledWith(options.env);
	
		expect(updateEnvironmentAssetInZip).toHaveBeenCalledWith(outputBuffers.testZipBuffer, mockEnvMap, DEPENDENCY_DIRECTORY);
	
		expect(writeArchive).toHaveBeenCalledWith(
			'projectA,projectB',
			false,
			'projA,projB',
			outputBuffers.testZipBuffer,
			outputBuffers.buildZipBuffer
		);
	});
	
	it('should enable debug mode when debug is true', async () => {
		const optionsWithDebug = { ...options, debug: true };
	
		const mockDebugManagerInstance = {
			setDebugEnabled: jest.fn(),
			isDebugEnabled: jest.fn().mockReturnValue(true),
		};
		(DebugManager.getInstance as jest.Mock).mockReturnValue(mockDebugManagerInstance);
	
		await testAction(projects, optionsWithDebug);
	
		expect(mockDebugManagerInstance.setDebugEnabled).toHaveBeenCalledWith(true);
	});
	
	it('should not enable debug mode when debug is false', async () => {
		const optionsWithoutDebug = { ...options, debug: false };

		await testAction(projects, optionsWithoutDebug);

		expect(DebugManager.getInstance().setDebugEnabled).not.toHaveBeenCalled();
	});
	it('should call handleTestAssetsForEndpoints when options.endpoint is given ', async () => {
        const optionsEndpoint = { ...options, endpoints: 'http://gcgcg.com', names: 'helloTest' };
		await testAction(projects, optionsEndpoint);
		expect(testAssetsForEndpoint).toHaveBeenCalledWith(optionsEndpoint, projects, optionsEndpoint.localDir);
		expect(handleTestAssets).not.toHaveBeenCalled();
	});


});