import AdmZip from 'adm-zip';
import { showInfo, showError } from '../../helpers/common/message-helper.js';
import {
	checkForRootDirPermission,
	checkIfAllProjectExists,
	checkIfRootDirExists
} from '../../helpers/apim/root-dir-helper.js';
import {
	API_DEPENDENCY_IDENTIFIED,
	ASSERT_ADDED,
	CHECKING_FOR_PROJECT,
	CHECKING_ROOT_DIRECTORY,
	FAILED_TO_BUILD_TEST_ASSETS,
	INVALID_ASSET_KIND_TEST,
	NO_API_ASSET_REF_FOUND
} from '../../constants/message-constants.js';
import { checkAndLoadDependencies, searchAsset } from '../../helpers/apim/build-helper.js';
import { KindEnums } from '@apic/api-model/common/StudioEnums.js';
import { getSubDirectory, normalizePath } from '../../helpers/common/fs-helper.js';
import { COMMA } from '../../constants/app-constants.js';
import { isNullOrUndefined } from '../../helpers/common/data-helper.js';
import fs from 'fs';
import { cropPrefix } from '../../helpers/common/string-helper.js';
import {getAPIRefToBuild } from '../../helpers/apim/test-helper.js';
import {DebugManager} from '../../debug/debug-manager.js';

export interface BuildTestAssetsResult {
    zipBuffer: Buffer;
    apiReference: string;
}

const executeBuildTestAssets = async (rootDirPath: string, project: string, assets: string): Promise<BuildTestAssetsResult> => {
	try {
		// Validate rootDirPath
		if(DebugManager.getInstance().isDebugEnabled()) {
			showInfo(CHECKING_ROOT_DIRECTORY);
		}
		checkIfRootDirExists(rootDirPath);
		checkForRootDirPermission(rootDirPath);

		// Validate projectNames
		if(DebugManager.getInstance().isDebugEnabled()) {
			showInfo(CHECKING_FOR_PROJECT);
		}
		checkIfAllProjectExists(rootDirPath, project);

		// Create a new zip file
		const zipFile = new AdmZip();

		// Check and add test assets
		const apiReference = checkAndAddTestAssets(assets, project, rootDirPath, zipFile);

		// Check and Load Dependencies
		checkAndLoadDependencies(rootDirPath, project, zipFile, false);

		// Create a zip buffer
		const zipBuffer = zipFile.toBuffer();

		return { zipBuffer, apiReference };
	} catch (error: unknown) {
		showError((error as Error).message);
		throw new Error(FAILED_TO_BUILD_TEST_ASSETS);
	}
};

function addTestDefinition(asset: string, projectDirPath: string, rootDirPath: string, zipFile: AdmZip): fs.Dirent {
	const result = searchAsset(KindEnums.Test, asset, projectDirPath) as fs.Dirent;

	if (!result) {
		throw new Error(`Asset ${asset} not found in the project directory.`);
	}

	const filePath = normalizePath(`${result.parentPath}/${result.name}`);
	const zipPath = `${cropPrefix(result.parentPath, normalizePath(rootDirPath))}`;
	if(DebugManager.getInstance().isDebugEnabled()){
		showInfo(`${ASSERT_ADDED} ${asset}`);
	}
	zipFile.addLocalFile(filePath, zipPath);
	return result;
}


const checkAndAddTestAssets = (assets: string, project: string, rootDirPath: string, zipFile: AdmZip): string => {
	const projectDirPath = getSubDirectory(rootDirPath, project);
	const invalidAsset = assets.split(COMMA).find((asset) =>
		isNullOrUndefined(searchAsset(KindEnums.Test, asset, projectDirPath))
	);

	if (!isNullOrUndefined(invalidAsset)) {
		showError(`${INVALID_ASSET_KIND_TEST} ${invalidAsset}`);
	}

	const apiReferences: string[] = [];
	assets.split(COMMA).forEach((asset) => {
		const result = addTestDefinition(asset, projectDirPath, rootDirPath, zipFile);
		const filePath = normalizePath(`${result.parentPath}/${result.name}`);
		if (filePath) {
			const apiAssetRef = getAPIRefToBuild(filePath);
			if (apiAssetRef) {
				if(DebugManager.getInstance().isDebugEnabled()){
					showInfo(`${API_DEPENDENCY_IDENTIFIED} '${apiAssetRef}' `);
				}
				apiReferences.push(...apiAssetRef);
			} else {
				showError(NO_API_ASSET_REF_FOUND);
			}
		}
	});
	return apiReferences.join(COMMA);
};

export { executeBuildTestAssets };
