package de.accso.flexinale.shared_code_for_test;

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.backoffice.infrastructure.persistence.KinoEntity;
import de.accso.flexinale.backoffice.infrastructure.persistence.KinoSaalEntity;
import de.accso.flexinale.common.shared_kernel.DoNotCheckInArchitectureTests;
import de.accso.flexinale.common.shared_kernel.Identifiable;
import de.accso.flexinale.common.shared_kernel.Versionable;
import de.accso.flexinale.security.infrastructure.persistence.BenutzerEntity;
import de.accso.flexinale.ticketing.domain.model.Kontingent;
import de.accso.flexinale.ticketing.domain.model.Ticket;

import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;

import static de.accso.flexinale.common.shared_kernel.Identifiable.Id.uuidString;

@DoNotCheckInArchitectureTests
public final class TestDataBuilder {

    public static Film createFilm() {
        return createFilm("testfilm", "testurl", 42);
    }

    public static Film createFilm(String titel, String imdbUrl, Integer dauerInMinuten) {
        return new Film(Identifiable.Id.of(), new Film.Titel(titel), new Film.ImdbUrl(imdbUrl), new Film.DauerInMinuten(dauerInMinuten));
    }

    public static Kino createKinoWithKinosaele() {
        return createKinoWithKinosaele(120, 111, 112);
    }

    public static Kino createKinoWithKinosaele(int... anzahlPlaetze) {
        Kino kino = new Kino(Identifiable.Id.of(), new Kino.Name("Helion"),
                new Kino.Adresse("Kinostrasse 1"),
                new Kino.EmailAdresse("contact.helion@fl.ex"), new HashSet<>());

        Set<KinoSaal> saele = new HashSet<>();
        int counter = 1;
        for (int anzahl: anzahlPlaetze) {
            saele.add(
                new KinoSaal(Identifiable.Id.of(), new KinoSaal.Name("saal " + counter), new KinoSaal.AnzahlPlaetze(anzahl), kino));
        }
        kino.addSaele(saele);

        return kino;
    }

    public static KinoEntity createKinoEntityWithKinosaele() {
        return createKinoEntityWithKinosaele(120, 111, 112);
    }

    public static KinoEntity createKinoEntityWithKinosaele(int... anzahlPlaetze) {
        KinoEntity kino = new KinoEntity(uuidString(), Versionable.unknownVersion().version(), "Helion", "Kinostrasse 1",
                "contact.helion@fl.ex");

        Set<KinoSaalEntity> saele = new HashSet<>();
        int counter = 1;
        for (int anzahl: anzahlPlaetze) {
            saele.add(new KinoSaalEntity(uuidString(), Versionable.unknownVersion().version(), "saal " + counter, anzahl, kino));
        }
        kino.kinoSaele = saele;

        return kino;
    }

    public static BenutzerEntity createBenutzerEntity() {
        String benutzerId = Identifiable.Id.of().id();
        return new BenutzerEntity(benutzerId,
                "testlogin" + benutzerId, // needs to be unique
                "test" + benutzerId + "@fl.ex",   // needs to be unique
                "testname", "testvorname");
    }

    public static Vorfuehrung createVorfuehrung() {
        KinoSaal kinoSaal = createKinoWithKinosaele(100).kinoSaele.iterator().next();
        return createVorfuehrung(LocalDateTime.now(), createFilm(), kinoSaal);
    }

    public static Vorfuehrung createVorfuehrung(LocalDateTime zeit, Film film, KinoSaal kinoSaal) {
        return new Vorfuehrung(Identifiable.Id.of(), new Vorfuehrung.Zeit(zeit), film, kinoSaal);
    }

    public static Ticket createTicket(Film film, Vorfuehrung vorfuehrung, BenutzerEntity besucher) {
        return createTicket(film, vorfuehrung, besucher, Ticket.VerkaufsKanal.ONLINE);
    }

    public static Ticket createTicket(Film film, Vorfuehrung vorfuehrung, BenutzerEntity besucher, Ticket.VerkaufsKanal kanal) {
        return new Ticket(Identifiable.Id.of(), film.id(), vorfuehrung.id(), Identifiable.Id.of(besucher.id), kanal);
    }

    public static Kontingent createKontingent(int gesamtKapazitaetVerkauf, int quoteOnline, Vorfuehrung vorfuehrung) {
        return new Kontingent(Identifiable.Id.of(), gesamtKapazitaetVerkauf, quoteOnline, vorfuehrung.id());
    }

    public static Kontingent createKontingent(int restKontingentOnline, int restKontingentZentral,
                                              int restKontingentKinokasse, Vorfuehrung vorfuehrung) {
        return new Kontingent(Identifiable.Id.of(),
                new Kontingent.RestKontingent(restKontingentOnline),
                new Kontingent.RestKontingent(restKontingentZentral),
                new Kontingent.RestKontingent(restKontingentKinokasse),
                vorfuehrung.id());
    }
}
