package de.accso.flexinale.backoffice.api_in.rest;

import de.accso.flexinale.FlexinaleDistributedApplicationTestIntegrated;
import de.accso.flexinale.backoffice.domain.dao.FilmDao;
import de.accso.flexinale.backoffice.domain.dao.KinoDao;
import de.accso.flexinale.backoffice.domain.dao.VorfuehrungDao;
import de.accso.flexinale.backoffice.domain.model.Film;
import de.accso.flexinale.backoffice.domain.model.Kino;
import de.accso.flexinale.backoffice.domain.model.KinoSaal;
import de.accso.flexinale.backoffice.domain.model.Vorfuehrung;
import de.accso.flexinale.security.BenutzerDetailsService;
import de.accso.flexinale.security.infrastructure.persistence.BenutzerDao;
import de.accso.flexinale.security.infrastructure.persistence.BenutzerEntity;
import de.accso.flexinale.common.shared_kernel.DoNotCheckInArchitectureTests;
import de.accso.flexinale.shared_code_for_test.TestDataBuilder;
import de.accso.flexinale.ticketing.domain.dao.KontingentDao;
import de.accso.flexinale.ticketing.domain.model.Kontingent;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;

import java.time.LocalDateTime;

import static de.accso.flexinale.shared_code_for_test.TestDataBuilder.createFilm;
import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest(classes = {FlexinaleDistributedApplicationTestIntegrated.class})
@ActiveProfiles("test-integrated")
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS)
@DoNotCheckInArchitectureTests
class RestControllerRetrieveDataTest {

    @Autowired
    BenutzerDao benutzerDao;

    @Autowired
    BenutzerDetailsService benutzerDetailsService;

    @Autowired
    FilmDao filmDao;

    @Autowired
    KinoDao kinoDao;

    @Autowired
    VorfuehrungDao vorfuehrungDao;

    @Autowired
    KontingentDao kontingentDao;

    @Autowired
    FilmRestController filmRestController;

    @Autowired
    KinoKinoSaalRestController kinoKinoSaalRestController;

    @Autowired
    VorfuehrungRestController vorfuehrungRestController;

    @BeforeEach
    public void createBenutzerCredentials() {
        // arrange
        BenutzerEntity benutzer = TestDataBuilder.createBenutzerEntity();
        benutzer.encryptAndSetPassword("test");

        // act
        benutzerDao.save(benutzer);

        UserDetails userDetails = benutzerDetailsService.loadUserByUsername (benutzer.login);
        Authentication authToken = new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword(),
                userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authToken);
    }

    @Test
    void testSmokeIntegrationPersistenceAndRestForFilmTest() {
        // arrange
        Film film = createFilm();

        // act
        Film savedFilm = filmDao.save(film);

        // assert
        assertThat(savedFilm.equalsByContent(film)).isTrue();

        // act
        Film searchedFilm = filmRestController.film(film.id().id());

        // assert
        assertThat(searchedFilm.equalsByContent(film)).isTrue();
    }

    @Test
    void testSmokeIntegrationPersistenceAndRestForKinoKinoSaalTest() {
        // arrange
        Kino kino = TestDataBuilder.createKinoWithKinosaele(999);
        KinoSaal kinoSaal = kino.kinoSaele.iterator().next();

        // act
        Kino savedKino = kinoDao.save(kino);

        // assert
        assertThat(savedKino.equalsByContent(kino)).isTrue();

        // act
        Kino searchedKino = kinoKinoSaalRestController.kino(kino.id().id());

        // assert
        assertThat(searchedKino.equalsByContent(kino)).isTrue();
        assertThat(searchedKino.kinoSaele).hasSize(1);
        for (KinoSaal searchedKinoSaal : searchedKino.kinoSaele) {
            assertThat(searchedKinoSaal.equalsByContent(kinoSaal)).isTrue();
        }
    }

    @Test
    void testSmokeIntegrationPersistenceAndRestForVorfuehrungAndKontingentSaalTest() {
        // arrange
        Film film = TestDataBuilder.createFilm();
        Kino kino = TestDataBuilder.createKinoWithKinosaele(999);
        KinoSaal kinoSaal = kino.kinoSaele.iterator().next();

        Vorfuehrung vorfuehrung = TestDataBuilder.createVorfuehrung(LocalDateTime.now(), film, kinoSaal);

        Kontingent kontingent = TestDataBuilder.createKontingent(33, 33, 33, vorfuehrung);

        // act
        Film savedFilm = filmDao.save(film);
        Kino savedKino = kinoDao.save(kino);
        Vorfuehrung savedVorfuehrung = vorfuehrungDao.save(vorfuehrung);
        Kontingent savedKontingent = kontingentDao.save(kontingent);

        // assert
        assertThat(savedFilm.equalsByContent(film)).isTrue();
        assertThat(savedKino.equalsByContent(kino)).isTrue();
        assertThat(savedVorfuehrung.equalsByContent(vorfuehrung)).isTrue();
        assertThat(savedKontingent.equalsByContent(kontingent)).isTrue();

        // act
        Vorfuehrung searchedVorfuehrung = vorfuehrungRestController.vorfuehrung(vorfuehrung.id().id());

        // assert
        assertThat(searchedVorfuehrung.equalsByContent(vorfuehrung)).isTrue();
    }
}