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

import de.accso.flexinale.backoffice.api_contract.event.FilmCRUDEvent;
import de.accso.flexinale.backoffice.api_contract.event.FilmCreatedEvent;
import de.accso.flexinale.backoffice.api_contract.event.FilmDeletedEvent;
import de.accso.flexinale.backoffice.api_contract.event.FilmUpdatedEvent;
import de.accso.flexinale.backoffice.api_contract.event.model.FilmTO;
import de.accso.flexinale.backoffice.api_out.event.mapper.Film2FilmTOMapper;
import de.accso.flexinale.backoffice.domain.model.Film;
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 FilmPublisher implements EventPublisher3<FilmCreatedEvent, FilmUpdatedEvent, FilmDeletedEvent> {
    private final EventBus<FilmCreatedEvent> createBus;
    private final EventBus<FilmUpdatedEvent> updateBus;
    private final EventBus<FilmDeletedEvent> deleteBus;

    private final EventNotification notification;

    public FilmPublisher(final EventBusFactory eventBusFactory,
                         final EventNotification notification) {
        this.createBus = eventBusFactory.createOrGetEventBusFor(FilmCreatedEvent.class);
        this.updateBus = eventBusFactory.createOrGetEventBusFor(FilmUpdatedEvent.class);
        this.deleteBus = eventBusFactory.createOrGetEventBusFor(FilmDeletedEvent.class);

        this.notification = notification;
    }

    public void publishNewFilms(final Collection<Film> films) {
        publishCRUDEvents(films, FilmCRUDEvent.CRUD.CREATE);
    }

    public void publishUpdatedFilms(final Collection<Film> films) {
        publishCRUDEvents(films, FilmCRUDEvent.CRUD.UPDATE);
    }

    // currently we do not publish Deletions events
    public void publishDeletedFilms(final Collection<Film> films) {
        publishCRUDEvents(films, FilmCRUDEvent.CRUD.DELETE);
    }

    private void publishCRUDEvents(final Collection<Film> changedFilms, final FilmCRUDEvent.CRUD mode) {
        for (Film film: changedFilms) {
            FilmTO filmTO = Film2FilmTOMapper.map(film);
            switch (mode) {
                case CREATE -> this.post (FilmCreatedEvent.class, new FilmCreatedEvent(filmTO));
                case UPDATE -> this.post2(FilmUpdatedEvent.class, new FilmUpdatedEvent(filmTO));
                case DELETE -> this.post3(FilmDeletedEvent.class, new FilmDeletedEvent(filmTO));
            }
        }
    }

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

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

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

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