package eu.dnetlib.data.mdstore.manager.controller;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.springframework.web.util.UriComponentsBuilder;

import com.google.common.collect.Sets;

import eu.dnetlib.data.mdstore.manager.exceptions.MDStoreManagerException;
import eu.dnetlib.data.mdstore.manager.utils.DatabaseUtils;
import eu.dnetlib.data.mdstore.manager.utils.HdfsClient;

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class MDStoreControllerWithMocksTest {

	// Class Under Test
	private MDStoreController controller;

	@Mock
	private DatabaseUtils dbUtils;

	@Mock
	private HdfsClient hdfsClient;

	@BeforeEach
	void setUp() throws Exception {
		controller = new MDStoreController();
		controller.setDatabaseUtils(dbUtils);
		controller.setHdfsClient(hdfsClient);
		when(hdfsClient.listHadoopDirs()).thenReturn(Sets.newHashSet("/tmp/a", "/tmp/a/1", "/tmp/b", "/tmp/b/1", "/tmp/b/2", "/tmp/c"));
		when(dbUtils.listValidHdfsPaths()).thenReturn(Sets.newHashSet("/tmp/a", "/tmp/a/1", "/tmp/b", "/tmp/b/2"));
	}

	@Test
	void testFixHdfsInconsistencies_false() throws MDStoreManagerException {
		final Set<String> toDelete = controller.fixHdfsInconsistencies(false);
		assertEquals(2, toDelete.size());
		assertTrue(toDelete.contains("/tmp/b/1"));
		assertTrue(toDelete.contains("/tmp/c"));
		verify(hdfsClient, never()).deletePath(anyString());
	}

	@Test
	void testFixHdfsInconsistencies_true() throws MDStoreManagerException {
		final Set<String> toDelete = controller.fixHdfsInconsistencies(true);
		assertEquals(2, toDelete.size());
		assertTrue(toDelete.contains("/tmp/b/1"));
		assertTrue(toDelete.contains("/tmp/c"));
		verify(hdfsClient).deletePath("/tmp/b/1");
		verify(hdfsClient).deletePath("/tmp/c");
	}

	@Test
	void testUrlCreation() throws Exception {
		final String format = "oai_dc";
		final String layout = "store";
		final String interpretation = "native";
		final String dsName = "LAReferencia - Red Federada de Repositorios Institucionales de Publicaciones Científicas Latinoamericanas";
		final String dsId = "ds:123";
		final String apiId = "api:123:oai";

		final String urlBase1 = "https://beta.services.openaire.eu/mdstoremanager/mdstores/new/{format}/{layout}/{interpretation}";
		final String urlBase2 = "https://beta.services.openaire.eu/mdstoremanager/mdstores/new/%s/%s/%s?dsName=%s&dsId=%s&apiId=%s";

		final Map<String, Object> params = new HashMap<>();

		params.put("format", format);
		params.put("layout", layout);
		params.put("interpretation", interpretation);

		final URI uri = UriComponentsBuilder.fromUriString(urlBase1)
			.queryParam("dsName", dsName)
			.queryParam("dsId", dsId)
			.queryParam("apiId", apiId)
			.buildAndExpand(params)
			.toUri();

		final String url2 = String
			.format(urlBase2, URLEncoder.encode(format, StandardCharsets.UTF_8.name()), URLEncoder.encode(layout, StandardCharsets.UTF_8.name()), URLEncoder
				.encode(interpretation, StandardCharsets.UTF_8.name()), URLEncoder.encode(dsName, StandardCharsets.UTF_8.name()), URLEncoder
					.encode(dsId, StandardCharsets.UTF_8.name()), URLEncoder.encode(apiId, StandardCharsets.UTF_8.name()));

		System.out.println("URL using UriComponentsBuilder (toString)      : " + uri.toString());
		System.out.println("URL using UriComponentsBuilder (toASCIIString) : " + uri.toASCIIString());
		System.out.println("URL using URLEncoder                           : " + url2);
	}
}
