package de.accso.flexinale.ticketing.application.services;

import de.accso.flexinale.FlexinaleDistributedApplicationTestIntegrated;
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.common.shared_kernel.Identifiable;
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.application.services.TicketService;
import de.accso.flexinale.ticketing.domain.dao.KontingentDao;
import de.accso.flexinale.ticketing.domain.dao.TicketDao;
import de.accso.flexinale.ticketing.domain.model.Kontingent;
import de.accso.flexinale.ticketing.domain.model.Ticket;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

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

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

    @Autowired
    TicketService ticketService;

    @Autowired
    private TicketDao ticketDao;

     @Autowired
    private KontingentDao kontingentDao;

    private BenutzerEntity besucher;

    private final int quoteOnline = 33;

    @BeforeEach
    void prepareDataForTicketKauf() {
        // arrange for all tests
        besucher = TestDataBuilder.createBenutzerEntity();
    }

    @AfterEach
    void cleanupDatabase() {
        ticketDao.deleteAll();
        kontingentDao.deleteAll();
    }

    @Test
    void testLoeseGutscheineOnlineFuerVorfuehrungEin_Ticket() {
        // arrange
        Film film = TestDataBuilder.createFilm();
        Kino kino = TestDataBuilder.createKinoWithKinosaele(100);
        KinoSaal kinoSaal = kino.kinoSaele.iterator().next();
        Vorfuehrung vorfuehrung = TestDataBuilder.createVorfuehrung(LocalDateTime.now(), film, kinoSaal);

        int kontingentGesamt = 120;
        Kontingent kontingent = TestDataBuilder.createKontingent(kontingentGesamt, quoteOnline, vorfuehrung);
        kontingentDao.save(kontingent);

        int anzahlGutscheine = 10;

        // act
        ticketService.loeseGutscheineOnlineFuerVorfuehrungEin(vorfuehrung.id(), film.id(), besucher.id(), anzahlGutscheine);

        // assert
        int anzahlTickets = ticketDao.gesamtZahlDerTicketsFuer(Identifiable.Id.of(besucher.id));
        assertThat(anzahlTickets).isEqualTo(anzahlGutscheine);

        List<Ticket> tickets = ticketDao.findAll();
        assertThat(tickets.size()).isEqualTo(anzahlGutscheine);
    }

    @Test
    void testLoeseGutscheineOnlineFuerVorfuehrungEin_Kontingent() {
        // arrange
        Film film = TestDataBuilder.createFilm();
        Kino kino = TestDataBuilder.createKinoWithKinosaele(100);
        KinoSaal kinoSaal = kino.kinoSaele.iterator().next();
        Vorfuehrung vorfuehrung = TestDataBuilder.createVorfuehrung(LocalDateTime.now(), film, kinoSaal);

        int kontingentGesamt = 120;
        Kontingent kontingent = TestDataBuilder.createKontingent(kontingentGesamt, quoteOnline, vorfuehrung);
        kontingentDao.save(kontingent);

        int anzahlGutscheine = 10;

        // act
        ticketService.loeseGutscheineOnlineFuerVorfuehrungEin(vorfuehrung.id(), film.id(), besucher.id(), anzahlGutscheine);

        // assert
        Optional<Kontingent> kontingent1 = kontingentDao.findById(kontingent.id());
        assertThat(kontingent1.isPresent()).isTrue();
        assertThat(kontingent1.get().getRestKontingentOnline().raw()).isEqualTo(40 - anzahlGutscheine);
    }

}
