/*
 * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
 * Ministerpräsidenten des Landes Schleswig-Holstein
 * Staatskanzlei
 * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
 *
 * Lizenziert unter der EUPL, Version 1.2 oder - sobald
 * diese von der Europäischen Kommission genehmigt wurden -
 * Folgeversionen der EUPL ("Lizenz");
 * Sie dürfen dieses Werk ausschließlich gemäß
 * dieser Lizenz nutzen.
 * Eine Kopie der Lizenz finden Sie hier:
 *
 * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
 *
 * Sofern nicht durch anwendbare Rechtsvorschriften
 * gefordert oder in schriftlicher Form vereinbart, wird
 * die unter der Lizenz verbreitete Software "so wie sie
 * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
 * ausdrücklich oder stillschweigend - verbreitet.
 * Die sprachspezifischen Genehmigungen und Beschränkungen
 * unter der Lizenz sind dem Lizenztext zu entnehmen.
 */
package de.ozgcloud.admin.setting;

import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;

import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;

import de.ozgcloud.admin.organisationseinheit.OrganisationsEinheitSettings;
import de.ozgcloud.admin.organisationseinheit.OrganisationsEinheitSettingsTestFactory;
import de.ozgcloud.admin.organisationseinheit.OrganisationsEinheitTestFactory;
import de.ozgcloud.admin.setting.postfach.AbsenderVorgangManagerTestFactory;
import de.ozgcloud.admin.setting.postfach.PostfachSettingBody;
import de.ozgcloud.admin.setting.postfach.PostfachSettingBodyTestFactory;

class SettingServiceTest {

	@InjectMocks
	@Spy
	private SettingService service;

	@Mock
	private SettingRepository repository;
	@Mock
	private OrganisationsEinheitSettingsRepository organisationsEinheitSettingsRepository;

	@Mock
	private SettingMapper mapper;

	private final PostfachSettingBody postfach = PostfachSettingBodyTestFactory.create();

	@Nested
	class TestGetAlfaSettingDTO {

		@Captor
		private ArgumentCaptor<AlfaSettingDTO.AlfaSettingDTOBuilder> alfaBuilderCaptor;

		private final AlfaSettingDTO alfaSetting = AlfaSettingDTOTestFactory.create();
		private final Map<String, OrganisationsEinheitSettings> organisationsEinheitSettings = Map.of(
				OrganisationsEinheitTestFactory.ORGANISATIONS_EINHEIT_ID,
				OrganisationsEinheitSettingsTestFactory.create());

		@BeforeEach
		void init() {
			doReturn(organisationsEinheitSettings).when(service).getOrganisationsEinheitSettings();
			doReturn(postfach).when(service).getSettingWithPostfachFromDb();
		}

		@Test
		void shouldCallGetSettingWithPostfachFromDb() {
			service.getAlfaSettingDTO();

			verify(service).getSettingWithPostfachFromDb();
		}

		@Test
		void shouldGetOrganisationsEinheitSettings() {
			service.getAlfaSettingDTO();

			verify(service).getOrganisationsEinheitSettings();
		}

		@Test
		void shouldReturnBuiltAlfaSettingDTO() {
			var resultSettingDTO = service.getAlfaSettingDTO();

			assertThat(resultSettingDTO).usingRecursiveComparison().isEqualTo(alfaSetting);
		}
	}

	@Nested
	class TestGetVorgangManagerSettingDTO {

		@Captor
		private ArgumentCaptor<VorgangManagerSettingDTO.VorgangManagerSettingDTOBuilder> vorgangManagerBuilderCaptor;

		private final VorgangManagerSettingDTO vorgangManagerSetting = VorgangManagerSettingDTOTestFactory.create();
		private final Map<String, OrganisationsEinheitSettings> organisationsEinheitSettings = Map.of(
				OrganisationsEinheitTestFactory.ORGANISATIONS_EINHEIT_ID,
				OrganisationsEinheitSettingsTestFactory.create());

		@BeforeEach
		void init() {
			doReturn(organisationsEinheitSettings).when(service).getOrganisationsEinheitSettings();
			doReturn(postfach).when(service).getSettingWithPostfachFromDb();
			when(mapper.mapAbsenderToAbsenderVorgangManager(postfach.getAbsender())).thenReturn(AbsenderVorgangManagerTestFactory.create());
		}

		@Test
		void shouldCallGetSettingWithPostfachFromDb() {
			service.getVorgangManagerSettingDTO();

			verify(service).getSettingWithPostfachFromDb();
		}

		@Test
		void shouldGetOrganisationsEinheitSettings() {
			service.getVorgangManagerSettingDTO();

			verify(service).getOrganisationsEinheitSettings();
		}

		@Test
		void shouldReturnBuiltVorgangManagerSettingDTO() {
			var resultSettingDTO = service.getVorgangManagerSettingDTO();

			assertThat(resultSettingDTO).usingRecursiveComparison().isEqualTo(vorgangManagerSetting);
		}

	}

	@Nested
	class TestGetSettingWithPostfachFromDb {

		private static final String POSTFACH = "Postfach";

		private final Setting emptyPostfachSetting = SettingTestFactory.createBuilder().name(POSTFACH).build();
		private final Setting postfachSettingWithBody = SettingTestFactory.createBuilder().name(POSTFACH).settingBody(postfach).build();

		@Test
		void shouldCallRepository() {
			when(repository.findOneByName(POSTFACH)).thenReturn(Optional.of(postfachSettingWithBody));

			service.getSettingWithPostfachFromDb();

			verify(repository).findOneByName(POSTFACH);
		}

		@Test
		void shouldReturnPostfachSettingBody() {
			when(repository.findOneByName(POSTFACH)).thenReturn(Optional.of(postfachSettingWithBody));

			var returnedBody = service.getSettingWithPostfachFromDb();

			assertThat(returnedBody).isEqualTo(postfach);
		}

		@Test
		void shouldReturnEmptyPostfachSettingBodyWhenSettingNotFound() {
			when(repository.findOneByName(POSTFACH)).thenReturn(Optional.empty());

			var returnedBody = service.getSettingWithPostfachFromDb();

			assertThat(returnedBody).usingRecursiveComparison().isEqualTo(PostfachSettingBody.builder().build());
		}

		@Test
		void shouldReturnEmptyPostfachSettingBodyForSettingWithoutBody() {
			when(repository.findOneByName(POSTFACH)).thenReturn(Optional.of(emptyPostfachSetting));

			var returnedBody = service.getSettingWithPostfachFromDb();

			assertThat(returnedBody).usingRecursiveComparison().isEqualTo(PostfachSettingBody.builder().build());
		}
	}

	@Nested
	class TestGetOrganisationsEinheitSettings {

		private final OrganisationsEinheitWithSettings organisationsEinheitWithSettings = OrganisationsEinheitWithSettingsTestFactory.create();

		@Test
		void shouldReturnOrganisationsEinheitSettingsByOrganisationsEinheitId() {
			when(organisationsEinheitSettingsRepository.getSettings()).thenReturn(Stream.of(organisationsEinheitWithSettings));

			var got = service.getOrganisationsEinheitSettings();

			assertThat(got).contains(entry(organisationsEinheitWithSettings.organisationsEinheitId(), organisationsEinheitWithSettings.settings()));
		}

		@Test
		void shouldReturnEmpty() {
			when(organisationsEinheitSettingsRepository.getSettings()).thenReturn(Stream.of());

			var got = service.getOrganisationsEinheitSettings();

			assertThat(got).isEmpty();

		}
	}
}