package de.accso.flexinale.ticketing.api_in.event;

import de.accso.flexinale.besucherportal.api_contract.event.GutscheinEinloesenBeauftragtEvent;
import de.accso.flexinale.common.api.eventbus.EventBus;
import de.accso.flexinale.common.api.eventbus.EventBusFactory;
import de.accso.flexinale.common.api.eventbus.EventNotification;
import de.accso.flexinale.common.api.eventbus.EventSubscriber;
import de.accso.flexinale.common.application.caching.InMemoryCache;
import de.accso.flexinale.common.api.event.Event;
import de.accso.flexinale.common.shared_kernel.Identifiable;
import de.accso.flexinale.ticketing.application.services.TicketService;
import de.accso.flexinale.ticketing.domain.model.KontingentBereitsAusgeschoepftException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static de.accso.flexinale.common.api.eventbus.EventSubscriptionAtStart.START_READING_FROM_LAST_TIME;
import static de.accso.flexinale.common.shared_kernel.RawWrapper.getRawOrNull;

@SuppressWarnings("unused")
public class GutscheinEinloesenBeauftragtSubscriber implements EventSubscriber<GutscheinEinloesenBeauftragtEvent> {
    private static final Logger LOGGER = LoggerFactory.getLogger(GutscheinEinloesenBeauftragtSubscriber.class);

    private final TicketService ticketService;

    // caches are currently never cleared - might want to use Cache implementation with automatic time-to-live
    private final InMemoryCache<Identifiable.Id, Event> gutscheinEinloesenEventCache;

    private final EventNotification notification;

    public GutscheinEinloesenBeauftragtSubscriber(final EventBusFactory eventBusFactory,
                                                  final TicketService ticketService,
                                                  final EventNotification notification) {
        EventBus<GutscheinEinloesenBeauftragtEvent> eventBus =
                eventBusFactory.createOrGetEventBusFor(GutscheinEinloesenBeauftragtEvent.class);
        eventBus.subscribe(GutscheinEinloesenBeauftragtEvent.class, this, START_READING_FROM_LAST_TIME);

        this.ticketService = ticketService;
        this.notification = notification;
        this.gutscheinEinloesenEventCache = new InMemoryCache<>();
    }

    @Override
    public String getName() {
        return GutscheinEinloesenBeauftragtSubscriber.class.getName();
    }

    @Override
    public String getGroupName() {
        return "flexinale-distributed-ticketing"; //TODO make configurable, use "spring.kafka.consumer.group-id" from application.properties
    }

    @Override
    public void receive(final GutscheinEinloesenBeauftragtEvent event) {
        LOGGER.debug("received new event " + event);

        this.notification.notify(event);

        // idem potence - do not buy same tickets twice
        if (gutscheinEinloesenEventCache.containsKey(event.correlationId())) {
            LOGGER.info(("received GutscheinEinloesenBeauftragtEvent twice with same correlationId=%s , " +
                    "so already handled. Ignore and do nothing here.").formatted(event.correlationId()));
            return;
        }

        gutscheinEinloesenEventCache.put(event.correlationId(), event);

        try {
            ticketService.loeseGutscheineOnlineFuerVorfuehrungEin(
                    event.gutscheinEinloesenAuftrag.vorfuehrungId(),
                    event.gutscheinEinloesenAuftrag.filmId(),
                    event.gutscheinEinloesenAuftrag.besucherId(),
                    getRawOrNull(event.gutscheinEinloesenAuftrag.anzahlTickets()));
        }
        catch (KontingentBereitsAusgeschoepftException kbaEx) {
            LOGGER.info("Could not get %s tickets for Vorfuehrung %s, Film %s for Besucher %s: Kontingent bereits ausgeschöpft"
                    .formatted(getRawOrNull(event.gutscheinEinloesenAuftrag.anzahlTickets()),
                            event.gutscheinEinloesenAuftrag.vorfuehrungId(), event.gutscheinEinloesenAuftrag.filmId(),
                            event.gutscheinEinloesenAuftrag.besucherId()));
        }
    }
}
