package de.ozgcloud.admin.environment;

import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import de.ozgcloud.admin.RootController;
import lombok.SneakyThrows;

@ExtendWith(MockitoExtension.class)
class EnvironmentControllerTest {

	@Spy
	@InjectMocks
	private EnvironmentController controller;

	@Mock
	private ProductionProperties environmentProperties;
	@Mock
	private OAuth2Properties oAuth2Properties;

	private MockMvc mockMvc;

	@BeforeEach
	void mock() {
		mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
	}

	@Nested
	class TestGetEnvironment {
		@SneakyThrows
		@Test
		void shouldReturnOk() {
			when(environmentProperties.isProduction()).thenReturn(true);

			var response = doRequest();

			response.andExpect(status().isOk());
		}

		@Nested
		class TestBody {

			@Test
			@SneakyThrows
			void shouldCallIsProduction() {
				when(environmentProperties.isProduction()).thenReturn(true);

				doRequest();

				verify(environmentProperties).isProduction();
			}

			@ParameterizedTest
			@ValueSource(booleans = { true, false })
			@SneakyThrows
			void shouldContainProduction(boolean production) {
				when(environmentProperties.isProduction()).thenReturn(production);

				var response = doRequest();

				response.andExpect(jsonPath("$.production").value(production));
			}
		}

		@Test
		@SneakyThrows
		void shouldContainURLToRoot() {
			var response = doRequest();

			response.andExpect(jsonPath("$.remoteHost").value("http://localhost" + RootController.PATH));
		}

		@SneakyThrows
		@Test
		void shouldContainAuthServerUrl() {
			var oAuthServerUrl = "dummyOAuthUrl";
			when(oAuth2Properties.getAuthServerUrl()).thenReturn(oAuthServerUrl);

			var response = doRequest();

			response.andExpect(jsonPath("$.authServer").value(oAuthServerUrl));
		}

		@SneakyThrows
		@Test
		void shouldContainRealm() {
			var realm = "dummyRealm";
			when(oAuth2Properties.getRealm()).thenReturn(realm);

			var response = doRequest();

			response.andExpect(jsonPath("$.realm").value(realm));
		}

		@SneakyThrows
		@Test
		void shouldContainClientId() {
			var clientId = "dummdyClientId";
			when(oAuth2Properties.getResource()).thenReturn(clientId);

			var response = doRequest();

			response.andExpect(jsonPath("$.clientId").value(clientId));
		}

		@SneakyThrows
		private ResultActions doRequest() {
			return mockMvc.perform(get(EnvironmentController.PATH));
		}

	}

}