/*******************************************************************************
 * Copyright (c) 2017, 2020 Red Hat, Inc.
 *
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributor:
 *     Red Hat, Inc. - initial API and implementation
 ******************************************************************************/
package org.eclipse.linuxtools.docker.integration.tests.mock;

import org.eclipse.linuxtools.docker.core.EnumDockerConnectionState;
import org.eclipse.linuxtools.docker.core.IDockerConnection;
import org.eclipse.linuxtools.docker.core.IDockerImageInfo;
import org.eclipse.linuxtools.internal.docker.core.DockerClientFactory;
import org.eclipse.linuxtools.internal.docker.core.DockerConnection;
import org.eclipse.linuxtools.internal.docker.core.TCPConnectionSettings;
import org.eclipse.linuxtools.internal.docker.core.UnixSocketConnectionSettings;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;

import org.mandas.docker.client.DockerClient;
import org.mandas.docker.client.exceptions.DockerCertificateException;

public class MockDockerConnection {

	/**
	 * Factory for mocked {@link IDockerConnection}
	 */

	public static Builder from(final String name, final DockerClient dockerClient) {
		return new Builder(name, dockerClient);
	}

	public static class Builder {

		private final DockerConnection.Builder connectionBuilder;

		private final DockerClient dockerClient;

		private Builder(final String name, final DockerClient dockerClient) {
			this.connectionBuilder = new DockerConnection.Builder().name(name);
			this.dockerClient = dockerClient;
		}

		public DockerConnection withUnixSocketConnectionSettings(final String pathToSocket) {
			final DockerConnection connection = Mockito
					.spy(connectionBuilder.unixSocketConnection(new UnixSocketConnectionSettings(pathToSocket)));
			configureDockerClientFactory(connection, this.dockerClient);
			configureMockBehaviour(connection);
			return connection;
		}

		public DockerConnection withDefaultTCPConnectionSettings() {
			return withTCPConnectionSettings(null, null);
		}

		public DockerConnection withTCPConnectionSettings(final String host, final String pathToCerts) {
			final DockerConnection connection = Mockito
					.spy(connectionBuilder.tcpConnection(new TCPConnectionSettings(host, pathToCerts)));
			configureDockerClientFactory(connection, this.dockerClient);
			configureMockBehaviour(connection);
			return connection;
		}

		public DockerConnection withState(final EnumDockerConnectionState state) {
			final DockerConnection connection = withDefaultTCPConnectionSettings();
			Mockito.when(connection.getState()).thenReturn(state);
			return connection;
		}

		private static void configureMockBehaviour(final DockerConnection connection) {
			final IDockerImageInfo imageInfo = Mockito.mock(IDockerImageInfo.class, Mockito.RETURNS_DEEP_STUBS);
			Mockito.when(connection.getImageInfo(ArgumentMatchers.anyString())).thenReturn(imageInfo);
			// Mockito.when(connection.isOpen()).thenReturn(state ==
			// EnumDockerConnectionState.ESTABLISHED);
		}

		private static void configureDockerClientFactory(final DockerConnection connection,
				final DockerClient dockerClient) {
			final DockerClientFactory dockerClientFactory = Mockito.mock(DockerClientFactory.class);
			connection.setDockerClientFactory(dockerClientFactory);
			try {
				// return dockerClient without auth
				Mockito.when(dockerClientFactory.getClient(ArgumentMatchers.any())).thenReturn(dockerClient);
				// return same dockerClient with auth arg
				Mockito.when(dockerClientFactory.getClient(ArgumentMatchers.any(), ArgumentMatchers.any())).thenReturn(dockerClient);
			} catch (DockerCertificateException e) {
				// rest assured, nothing will happen while mocking the
				// DockerClientFactory
			}
		}

	}

}
