package testdata;

import de.accso.flexinale.FlexinaleMonolithApplication;
import de.accso.flexinale.data.services.*;
import de.accso.flexinale.data.model.Kino;
import de.accso.flexinale.data.model.KinoSaal;
import de.accso.flexinale.data.persistence.BenutzerDao;
import de.accso.flexinale.data.persistence.FilmDao;
import de.accso.flexinale.data.persistence.KinoDao;
import de.accso.flexinale.data.persistence.VorfuehrungDao;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest(classes = {FlexinaleMonolithApplication.class})
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS)
@ExtendWith(SpringExtension.class)
public class TestDataLoader {
    private static final String xlsDataFile = "/testdata/TestData.xlsx";

    @Autowired
    private BenutzerUploadService benutzerUploadService;

    @Autowired
    private KinoUploadService kinoUploadService;

    @Autowired
    private KinoSaalUploadService kinoSaalUploadService;

    @Autowired
    private FilmUploadService filmUploadService;

    @Autowired
    private VorfuehrungUploadService vorfuehrungUploadService;

    @Autowired
    private BenutzerDao benutzerDao;

    @Autowired
    private KinoDao kinoDao;

    @Autowired
    private FilmDao filmDao;

    @Autowired
    private VorfuehrungDao vorfuehrungDao;

    @Value("${spring.jpa.hibernate.ddl-auto}")
    private String springJpaHibernateDdlAuto;

    @Test
    void loadBenutzerAndFilmeAndKinosAndVorfuehrungenTestDataAndPersistToDatabase() throws IOException {
        // All data in the database is automatically deleted because of the property
        //     spring.jpa.hibernate.ddl-auto=create
        // in the test application.properties
        assertThat(springJpaHibernateDdlAuto).isEqualTo("create");

        // Loading: order is important because of foreign key relations
        loadBenutzerTestDataAndPersistToDatabase();
        loadFilmeTestDataAndPersistToDatabase();
        loadKinosAndKinoSaeleTestDataAndPersistToDatabase();
        loadVorfuehrungenTestDataAndPersistToDatabase();
    }

    private void loadBenutzerTestDataAndPersistToDatabase() throws IOException {
        // arrange
        // act
        int numPersistedBesucher = benutzerUploadService.
                loadDataFromExcelSheetAndPersist(xlsDataFile, PersistMode.UPDATE);

        // assert
        assertThat(benutzerDao.findAll()).hasSizeGreaterThanOrEqualTo(11);
        assertThat(numPersistedBesucher).isEqualTo(11);
    }

    private void loadFilmeTestDataAndPersistToDatabase() throws IOException {
        // arrange
        // act
        int numPersistedFilms = filmUploadService.
                loadDataFromExcelSheetAndPersist(xlsDataFile, PersistMode.UPDATE);

        // assert
        assertThat(filmDao.findAll()).hasSize(26);
        assertThat(numPersistedFilms).isEqualTo(26);
    }

    private void loadKinosAndKinoSaeleTestDataAndPersistToDatabase() throws IOException {
        // arrange
        // act
        Collection<KinoSaal> kinoSaele = kinoSaalUploadService.loadDataFromExcelSheet(xlsDataFile);
        Map<String, Collection<KinoSaal>> alleKinosUndIhreSaele = kinoSaalUploadService.mapKinoSaeleToKino(kinoSaele);

        // assert
        assertThat(alleKinosUndIhreSaele.keySet()).hasSize(10);
        alleKinosUndIhreSaele.keySet().forEach(kinoId -> {
            Collection<KinoSaal> saeleImKino = alleKinosUndIhreSaele.get(kinoId);
            assertThat(saeleImKino).hasSize(2);
            saeleImKino.forEach(kinoSaal -> assertThat(kinoSaal.anzahlPlaetze).isBetween(10, 100));
        });


        // arrange
        // act
        kinoUploadService.beforeLoad(alleKinosUndIhreSaele);
        int numPersistedKinos = kinoUploadService.
                loadDataFromExcelSheetAndPersist(xlsDataFile, PersistMode.UPDATE);
        kinoUploadService.afterLoad();

        // assert
        assertThat(numPersistedKinos).isEqualTo(10);

        List<Kino> alleKinos = kinoDao.findAll();
        assertThat(alleKinos).hasSizeGreaterThanOrEqualTo(10);
        assertThat(alleKinos.size()).isGreaterThanOrEqualTo(numPersistedKinos);

        for (String kinoId: alleKinosUndIhreSaele.keySet()) {
            Optional<Kino> optionalKino = kinoDao.findById(kinoId);
            assertThat(optionalKino.isEmpty()).isFalse();
            assertThat(optionalKino.get().kinoSaele).hasSize(2);
        }
    }

    private void loadVorfuehrungenTestDataAndPersistToDatabase() throws IOException {
        // arrange
        // act
        int numPersistedVorfuehrungen = vorfuehrungUploadService.
                loadDataFromExcelSheetAndPersist(xlsDataFile, PersistMode.UPDATE);

        // assert
        assertThat(vorfuehrungDao.findAll()).hasSize(52);
        assertThat(numPersistedVorfuehrungen).isEqualTo(52);
    }
}
