import {
	IDataObject,
	INodeExecutionData,
	ICredentialDataDecryptedObject
} from 'n8n-workflow';
import {
	IMongoCredentialsType,
	IMongoParametricCredentials,
	IMongoCredentials
} from './mongo.node.types';

/**
 * Standard way of building the MongoDB connection string, unless overridden with a provided string
 *
 * @param {ICredentialDataDecryptedObject} credentials MongoDB credentials to use, unless conn string is overridden
 */
function buildParameterizedConnString(
	credentials: IMongoParametricCredentials
): string {
	if (credentials.port) {
		return `mongodb://${credentials.user}:${credentials.password}@${credentials.host}:${credentials.port}`;
	} else {
		return `mongodb+srv://${credentials.user}:${credentials.password}@${credentials.host}`;
	}
}

/**
 * Build mongoDb connection string and resolve database name.
 * If a connection string override value is provided, that will be used in place of individual args
 *
 * @param {ICredentialDataDecryptedObject} credentials raw/input MongoDB credentials to use
 */
function buildMongoConnectionParams(
	credentials: IMongoCredentialsType
): IMongoCredentials {
	const sanitizedDbName =
		credentials.database && credentials.database.trim().length > 0
			? credentials.database.trim()
			: '';
	if (credentials.configurationType === 'connectionString') {
		if (
			credentials.connectionString &&
			credentials.connectionString.trim().length > 0
		) {
			return {
				connectionString: credentials.connectionString.trim(),
				database: sanitizedDbName
			};
		} else {
			throw new Error(
				'Cannot override credentials: valid MongoDB connection string not provided '
			);
		}
	} else {
		return {
			connectionString: buildParameterizedConnString(credentials),
			database: sanitizedDbName
		};
	}
}

/**
 * Verify credentials. If ok, build mongoDb connection string and resolve database name.
 *
 * @param {ICredentialDataDecryptedObject} credentials raw/input MongoDB credentials to use
 */
export function validateAndResolveMongoCredentials(
	credentials?: ICredentialDataDecryptedObject
): IMongoCredentials {
	if (credentials === undefined) {
		throw new Error('No credentials got returned!');
	} else {
		return buildMongoConnectionParams(
			credentials as unknown as IMongoCredentialsType,
		);
	}
}

/**
 * Returns of copy of the items which only contains the json data and
 * of that only the define properties
 *
 * @param {INodeExecutionData[]} items The items to copy
 * @param {string[]} properties The properties it should include
 * @returns
 */
export function getItemCopy(
	items: INodeExecutionData[],
	properties: string[]
): IDataObject[] {
	// Prepare the data to insert and copy it to be returned
	let newItem: IDataObject;
	return items.map(item => {
		newItem = {};
		for (const property of properties) {
			if (item.json[property] === undefined) {
				newItem[property] = null;
			} else {
				newItem[property] = JSON.parse(JSON.stringify(item.json[property]));
			}
		}
		return newItem;
	});
}