package de.accso.flexinale.backoffice.api_out.event;

import de.accso.flexinale.backoffice.api_contract.event.KinoCRUDEvent;
import de.accso.flexinale.backoffice.api_contract.event.KinoCreatedEvent;
import de.accso.flexinale.backoffice.api_contract.event.KinoDeletedEvent;
import de.accso.flexinale.backoffice.api_contract.event.KinoUpdatedEvent;
import de.accso.flexinale.backoffice.api_contract.event.model.KinoTO;
import de.accso.flexinale.backoffice.api_out.event.mapper.KinoKinoSaal2KinoKinoSaalTOMapper;
import de.accso.flexinale.backoffice.domain.model.Kino;
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.EventPublisher.EventPublisher3;

import java.util.Collection;

@SuppressWarnings("unused")
public class KinoPublisher implements EventPublisher3<KinoCreatedEvent, KinoUpdatedEvent, KinoDeletedEvent> {
    private final EventBus<KinoCreatedEvent> createBus;
    private final EventBus<KinoUpdatedEvent> updateBus;
    private final EventBus<KinoDeletedEvent> deleteBus;

    private final EventNotification notification;

    public KinoPublisher(final EventBusFactory eventBusFactory,
                         final EventNotification notification) {
        this.createBus = eventBusFactory.createOrGetEventBusFor(KinoCreatedEvent.class);
        this.updateBus = eventBusFactory.createOrGetEventBusFor(KinoUpdatedEvent.class);
        this.deleteBus = eventBusFactory.createOrGetEventBusFor(KinoDeletedEvent.class);

        this.notification = notification;
    }

    public void publishNewKinos(final Collection<Kino> kinos) {
        publishCRUDEvents(kinos, KinoCRUDEvent.CRUD.CREATE);
    }

    public void publishUpdatedKinos(final Collection<Kino> kinos) {
        publishCRUDEvents(kinos, KinoCRUDEvent.CRUD.UPDATE);
    }

    // currently we do not publish Deletions events
    public void publishDeletedKinos(final Collection<Kino> kinos) {
        publishCRUDEvents(kinos, KinoCRUDEvent.CRUD.DELETE);
    }

    private void publishCRUDEvents(final Collection<Kino> changedKinos, final KinoCRUDEvent.CRUD mode) {
        for (Kino kino: changedKinos) {
            KinoTO kinoTO = KinoKinoSaal2KinoKinoSaalTOMapper.mapKino(kino);
            switch (mode) {
                case CREATE -> this.post (KinoCreatedEvent.class, new KinoCreatedEvent(kinoTO));
                case UPDATE -> this.post2(KinoUpdatedEvent.class, new KinoUpdatedEvent(kinoTO));
                case DELETE -> this.post3(KinoDeletedEvent.class, new KinoDeletedEvent(kinoTO));
            }
        }
    }

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

    @Override
    public void post(final Class<KinoCreatedEvent> eventType, final KinoCreatedEvent event) {
        this.createBus.publish(eventType, event);
        this.notification.notify(event);
    }

    @Override
    public void post2(final Class<KinoUpdatedEvent> eventType, final KinoUpdatedEvent event) {
        this.updateBus.publish(eventType, event);
        this.notification.notify(event);
    }

    @Override
    public void post3(final Class<KinoDeletedEvent> eventType, final KinoDeletedEvent event) {
        this.deleteBus.publish(eventType, event);
        this.notification.notify(event);
    }
}
