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

import de.accso.flexinale.common.shared_kernel.FlexinaleIllegalArgumentException;
import de.accso.flexinale.common.shared_kernel.FlexinaleIllegalStateException;
import de.accso.flexinale.common.shared_kernel.Identifiable;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Optional;

public class TicketService {

    private static final Logger LOGGER = LoggerFactory.getLogger(TicketService.class);

    private final TicketDao ticketDao;

    private final KontingentDao kontingentDao;

    private final int quoteOnline;

    public TicketService(final TicketDao ticketDao,
                         final KontingentDao kontingentDao,
                         final int quoteOnline) {
        this.ticketDao = ticketDao;
        this.kontingentDao = kontingentDao;
        this.quoteOnline = quoteOnline;
    }

    public void loeseGutscheineOnlineFuerVorfuehrungEin(final Identifiable.Id vorfuehrungId, final Identifiable.Id filmId,
                                                        final Identifiable.Id besucherId,
                                                        final int anzahlGutscheine) {
        loeseGutscheineFuerVorfuehrungEin(vorfuehrungId, filmId, besucherId, anzahlGutscheine,
                Ticket.VerkaufsKanal.ONLINE);
    }

    @SuppressWarnings("SameParameterValue")
    private void loeseGutscheineFuerVorfuehrungEin(final Identifiable.Id vorfuehrungId, final Identifiable.Id filmId,
                                                   final Identifiable.Id besucherId,
                                                   final int anzahlGutscheine,
                                                   final Ticket.VerkaufsKanal verkaufsKanal) {
       Optional<Kontingent> kontingentOptional = kontingentDao.findByVorfuehrung(vorfuehrungId);

       if (kontingentOptional.isEmpty()) {
           String message = "Kontingent for Vorfuehrung %s could not be found".formatted(vorfuehrungId);
           LOGGER.error(message);
           throw new FlexinaleIllegalArgumentException(message);
       }

       Kontingent kontingent = kontingentOptional.get();

       Kontingent reduziertesKontingent = kontingent.reduziereKontingent(verkaufsKanal, anzahlGutscheine);
       kontingentDao.save(reduziertesKontingent);

       for (int i = 0; i < anzahlGutscheine; i++) {
            Ticket ticket = new Ticket(Identifiable.Id.of(), filmId, vorfuehrungId, besucherId, verkaufsKanal);
            ticketDao.save(ticket);
        }

        LOGGER.info("%d ticket(s) bought for Vorfuehrung with id %s, Besucher with id %s, using Verkaufskanal %s"
                .formatted(anzahlGutscheine, vorfuehrungId, besucherId, verkaufsKanal));
    }

    public List<Ticket> findByBesucherOrderByZeit(final Identifiable.Id besucherId) {
        return ticketDao.findByBesucherOrderByZeit(besucherId);
    }

    public void gebeVorfuehrungInDenVerkauf(final Identifiable.Id vorfuehrungId, final int kapazitaet) {
       if (kontingentDao.findByVorfuehrung(vorfuehrungId).isPresent()) {
           String message = "a Kontingent for Vorfuehrung %s already exists. No Kontingent created".formatted(vorfuehrungId);
           LOGGER.error(message);
           throw new FlexinaleIllegalStateException(message);
       }

        Kontingent kontingent = new Kontingent(Identifiable.Id.of(), kapazitaet, quoteOnline, vorfuehrungId);
        kontingentDao.save(kontingent);
    }
}
