/*
 * Copyright 2019 EPAM Systems
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.epam.ta.reportportal.core.integration.impl;

import com.epam.reportportal.extension.ReportPortalExtensionPoint;
import com.epam.ta.reportportal.commons.ReportPortalUser;
import com.epam.ta.reportportal.commons.validation.Suppliers;
import com.epam.ta.reportportal.core.integration.ExecuteIntegrationHandler;
import com.epam.ta.reportportal.core.integration.util.IntegrationService;
import com.epam.ta.reportportal.core.plugin.PluginBox;
import com.epam.ta.reportportal.dao.IntegrationRepository;
import com.epam.ta.reportportal.entity.integration.Integration;
import com.epam.ta.reportportal.exception.ReportPortalException;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.Map;

import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR;
import static com.epam.ta.reportportal.ws.model.ErrorType.INTEGRATION_NOT_FOUND;
import static java.util.Optional.ofNullable;

/**
 * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a>
 */
@Service
public class ExecuteIntegrationHandlerImpl implements ExecuteIntegrationHandler {

	private final Map<String, IntegrationService> integrationServiceMapping;

	private final IntegrationRepository integrationRepository;

	private final PluginBox pluginBox;

	private final IntegrationService basicIntegrationService;

	public ExecuteIntegrationHandlerImpl(IntegrationRepository integrationRepository, PluginBox pluginBox,
			@Qualifier("integrationServiceMapping") Map<String, IntegrationService> integrationServiceMapping,
			@Qualifier("basicIntegrationServiceImpl") IntegrationService basicIntegrationService) {
		this.integrationServiceMapping = integrationServiceMapping;
		this.integrationRepository = integrationRepository;
		this.pluginBox = pluginBox;
		this.basicIntegrationService = basicIntegrationService;
	}

	@Override
	public Object executeCommand(ReportPortalUser.ProjectDetails projectDetails, Long integrationId, String command,
			Map<String, ?> executionParams) {
		Integration integration = integrationRepository.findByIdAndProjectId(integrationId, projectDetails.getProjectId())
				.orElseGet(() -> integrationRepository.findGlobalById(integrationId)
						.orElseThrow(() -> new ReportPortalException(INTEGRATION_NOT_FOUND, integrationId)));

		IntegrationService integrationService = integrationServiceMapping.getOrDefault(integration.getType().getName(),
				basicIntegrationService
		);

		integrationService.decryptParams(integration);

		ReportPortalExtensionPoint pluginInstance = pluginBox.getInstance(integration.getType().getName(), ReportPortalExtensionPoint.class)
				.orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR,
						Suppliers.formattedSupplier("Plugin for '{}' isn't installed", integration.getType().getName()).get()
				));

		Object response = ofNullable(pluginInstance.getCommandToExecute(command)).map(it -> it.executeCommand(integration, executionParams))
				.orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR,
						Suppliers.formattedSupplier("Command '{}' is not found in plugin {}.", command, integration.getType().getName())
								.get()
				));

		integrationService.encryptParams(integration);

		return response;
	}
}

@@ -772,70 +772,8 @@
 er;%0A
-import com.epam.ta.reportportal.commons.validation.Suppliers;%0A
 impo
@@ -1157,24 +1157,88 @@
 lException;%0A
+import com.epam.ta.reportportal.ws.model.OperationCompletionRS;%0A
 import org.s
@@ -1358,16 +1358,150 @@
 il.Map;%0A
+import java.util.concurrent.CompletableFuture;%0A%0Aimport static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier;
 %0Aimport 
@@ -1866,16 +1866,68 @@
 dler %7B%0A%0A
+%09private static final String ASYNC_MODE = %22async%22;%0A%0A
 %09private
@@ -3504,34 +3504,24 @@
 RROR,%0A%09%09%09%09%09%09
-Suppliers.
 formattedSup
@@ -3609,16 +3609,108 @@
 %09%09%09));%0A%0A
+%09%09Boolean asyncMode = ofNullable((Boolean) executionParams.get(ASYNC_MODE)).orElse(false);%0A%0A
 %09%09Object
@@ -3786,16 +3786,75 @@
 ap(it -%3E
+ %7B%0A%09%09%09if (asyncMode) %7B%0A%09%09%09%09CompletableFuture.runAsync(() -%3E
  it.exec
@@ -3894,21 +3894,258 @@
 Params))
+;
 %0A%09%09%09%09
+return new OperationCompletionRS(formattedSupplier(%22Command '%7B%7D' accepted for processing in plugin%22,%0A%09%09%09%09%09%09command,%0A%09%09%09%09%09%09integration.getType().getName()%0A%09%09%09%09).get());%0A%09%09%09%7D%0A%09%09%09return it.executeCommand(integration, executionParams);%0A%09%09%7D)
 .orElseT
@@ -4208,20 +4208,8 @@
 %09%09%09%09
-%09%09Suppliers.
 form
@@ -4310,26 +4310,15 @@
 e())
-%0A%09%09%09%09%09%09%09%09
 .get()%0A
-%09%09
 %09%09))
@@ -4369,17 +4369,16 @@
 ation);%0A
-%0A
 %09%09return

Add possibility to call plugin commands async