/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.dlab.automation.cloud.gcp;

import com.epam.dlab.automation.exceptions.CloudException;
import com.epam.dlab.automation.helper.ConfigPropertyValue;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.compute.Compute;
import com.google.api.services.compute.model.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.testng.Assert;

import java.io.FileInputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.time.Duration;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class GcpHelper {

	private static final Logger LOGGER = LogManager.getLogger(GcpHelper.class);
	private static final Duration CHECK_TIMEOUT = Duration.parse("PT10m");
	private static final String LOCALHOST_IP = ConfigPropertyValue.get("LOCALHOST_IP");
	private static final String NOT_EXIST = "doesn't exist for this resource type";

	private GcpHelper() {
	}

	private static List<Instance> getInstances(String projectId, List<String> zones) throws IOException {
		List<Instance> instanceList = new ArrayList<>();
		for (String zone : zones) {
			Compute.Instances.List request = ComputeService.getInstance().instances().list(projectId, zone);
			InstanceList response;
			do {
				response = request.execute();
				if (response.getItems() == null) {
					continue;
				}
				instanceList.addAll(response.getItems());
				request.setPageToken(response.getNextPageToken());
			} while (response.getNextPageToken() != null);

		}
		return !instanceList.isEmpty() ? instanceList : null;
	}

	public static List<String> getInstancePrivateIps(Instance instance) {
		return instance.getNetworkInterfaces().stream().filter(Objects::nonNull)
				.map(NetworkInterface::getNetworkIP).filter(Objects::nonNull)
				.collect(Collectors.toList());
	}

	public static List<String> getInstancePublicIps(Instance instance) {
		return instance.getNetworkInterfaces()
				.stream().filter(Objects::nonNull)
				.map(NetworkInterface::getAccessConfigs)
				.filter(Objects::nonNull).map(Collection::stream)
				.flatMap(Function.identity()).filter(Objects::nonNull)
				.map(AccessConfig::getNatIP).filter(Objects::nonNull)
				.collect(Collectors.toList());
	}


	public static List<Instance> getInstancesByName(String name, String projectId, boolean restrictionMode,
													List<String> zones) throws IOException {
		if (ConfigPropertyValue.isRunModeLocal()) {
			List<Instance> mockedInstanceList = new ArrayList<>();
			Instance mockedInstance = mock(Instance.class);
			NetworkInterface mockedNetworkInterface = mock(NetworkInterface.class);
			when(mockedInstance.getNetworkInterfaces()).thenReturn(Collections.singletonList(mockedNetworkInterface));
			when(mockedInstance.getNetworkInterfaces().get(0).getNetworkIP()).thenReturn(LOCALHOST_IP);
			AccessConfig mockedAccessConfig = mock(AccessConfig.class);
			when(mockedInstance.getNetworkInterfaces().get(0).getAccessConfigs())
					.thenReturn(Collections.singletonList(mockedAccessConfig));
			when(mockedInstance.getNetworkInterfaces().get(0).getAccessConfigs().get(0).getNatIP())
					.thenReturn(LOCALHOST_IP);
			mockedInstanceList.add(mockedInstance);
			return mockedInstanceList;
		}
		List<Instance> instanceList = getInstances(projectId, zones);
		if (instanceList == null) {
			LOGGER.warn("There is not any virtual machine in GCP for project with id {}", projectId);
			return instanceList;
		}
		if (restrictionMode) {
			instanceList.removeIf(instance -> !hasName(instance, name));
		} else {
			instanceList.removeIf(instance -> !containsName(instance, name));
		}
		return !instanceList.isEmpty() ? instanceList : null;
	}

	private static boolean hasName(Instance instance, String name) {
		return instance.getName().equals(name);
	}

	private static boolean containsName(Instance instance, String name) {
		return instance.getName().contains(name);
	}

	private static String getStatus(Instance instance) {
		return instance.getStatus().toLowerCase();
	}

	public static void checkGcpStatus(String instanceName, String projectId, GcpInstanceState expGcpStatus, boolean
			restrictionMode, List<String> zones) throws InterruptedException, IOException {

		LOGGER.info("Check status of instance with name {} on GCP", instanceName);
		if (ConfigPropertyValue.isRunModeLocal()) {
			LOGGER.info("GCP instance with name {} fake status is {}", instanceName, expGcpStatus);
			return;
		}
		List<Instance> instancesWithName = getInstancesByName(instanceName, projectId, restrictionMode, zones);
		if (instancesWithName == null) {
			LOGGER.warn("There is not any instance in GCP with name {}", instanceName);
			return;
		}

		String instanceStatus;
		long requestTimeout = ConfigPropertyValue.getGcpRequestTimeout().toMillis();
		long timeout = CHECK_TIMEOUT.toMillis();
		long expiredTime = System.currentTimeMillis() + timeout;
		Instance instance = instancesWithName.get(0);
		while (true) {
			instanceStatus = getStatus(instance);
			if (instanceStatus.equalsIgnoreCase(expGcpStatus.toString())) {
				break;
			}
			if (timeout != 0 && expiredTime < System.currentTimeMillis()) {
				LOGGER.info("GCP instance with name {} state is {}", instanceName, getStatus(instance));
				throw new CloudException("Timeout has been expired for check status of GCP instance with " +
						"name " + instanceName);
			}
			Thread.sleep(requestTimeout);
		}

		for (Instance inst : instancesWithName) {
			LOGGER.info("GCP instance with name {} status is {}. Instance id {}, private IP {}, public " +
							"IP {}",
					instanceName, getStatus(inst), inst.getId(), (!getInstancePrivateIps(inst).isEmpty() ?
							getInstancePrivateIps(inst).get(0) : NOT_EXIST),
					(!getInstancePublicIps(inst).isEmpty() ? getInstancePublicIps(inst).get(0) : NOT_EXIST));
		}
		Assert.assertEquals(instanceStatus, expGcpStatus.toString(), "GCP instance with name " + instanceName +
				" status is not correct. Instance id " + instance.getId() + ", private IP " +
				(!getInstancePrivateIps(instance).isEmpty() ? getInstancePrivateIps(instance).get(0) : NOT_EXIST) +
				", public IP " +
				(!getInstancePublicIps(instance).isEmpty() ? getInstancePublicIps(instance).get(0) : NOT_EXIST));
	}

	public static List<String> getAvailableZonesForProject(String projectId) throws IOException {
		if (ConfigPropertyValue.isRunModeLocal()) {
			return Collections.emptyList();
		}
		List<Zone> zoneList = new ArrayList<>();
		Compute.Zones.List request = ComputeService.getInstance().zones().list(projectId);
		ZoneList response;
		do {
			response = request.execute();
			if (response.getItems() == null) {
				continue;
			}
			zoneList.addAll(response.getItems());
			request.setPageToken(response.getNextPageToken());
		} while (response.getNextPageToken() != null);
		return zoneList.stream().map(Zone::getDescription).collect(Collectors.toList());
	}

	private static class ComputeService {

		private static Compute instance;

		private ComputeService() {
		}

		static synchronized Compute getInstance() throws IOException {
			if (!ConfigPropertyValue.isRunModeLocal() && instance == null) {
				try {
					instance = createComputeService();
				} catch (GeneralSecurityException e) {
					LOGGER.info("An exception occured: {}", e);
				}
			}
			return instance;
		}

		private static Compute createComputeService() throws IOException, GeneralSecurityException {
			HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
			JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();

			GoogleCredential credential =
					GoogleCredential.fromStream(new FileInputStream(ConfigPropertyValue.getGcpAuthFileName()));
			if (credential.createScopedRequired()) {
				credential = credential.createScoped(
						Collections.singletonList("https://www.googleapis.com/auth/cloud-platform"));
			}

			return new Compute.Builder(httpTransport, jsonFactory, credential)
					.setApplicationName("Google-ComputeSample/0.1")
					.build();
		}

	}

}




