package p.studio.workspaces.framework;

import p.studio.lsp.events.StudioEvent;
import p.studio.lsp.events.StudioEventBus;
import p.studio.lsp.events.StudioWorkspaceEventBus;

import java.util.Objects;
import java.util.function.Consumer;

public final class StudioEventBindings {
    private final StudioSubscriptionBag subscriptions = new StudioSubscriptionBag();

    public void activate(Runnable registration) {
        Objects.requireNonNull(registration, "registration");
        if (!subscriptions.isEmpty()) {
            return;
        }
        registration.run();
    }

    public <T extends StudioEvent> void listen(
            StudioEventBus eventBus,
            Class<T> eventType,
            Consumer<? super T> consumer) {
        listen(eventBus, eventType).handle(consumer);
    }

    public <T extends StudioEvent> void listen(
            StudioWorkspaceEventBus eventBus,
            Class<T> eventType,
            Consumer<? super T> consumer) {
        listen(eventBus, eventType).handle(consumer);
    }

    public <T extends StudioEvent> Registration<T> listen(
            StudioEventBus eventBus,
            Class<T> eventType) {
        return new Registration<>(
                Objects.requireNonNull(eventBus, "eventBus"),
                Objects.requireNonNull(eventType, "eventType"));
    }

    public <T extends StudioEvent> Registration<T> listen(
            StudioWorkspaceEventBus eventBus,
            Class<T> eventType) {
        return new Registration<>(
                Objects.requireNonNull(eventBus, "eventBus"),
                Objects.requireNonNull(eventType, "eventType"));
    }

    public void clear() {
        subscriptions.clear();
    }

    public final class Registration<T extends StudioEvent> {
        private final StudioEventBus studioEventBus;
        private final StudioWorkspaceEventBus workspaceEventBus;
        private final Class<T> eventType;

        private Registration(StudioEventBus studioEventBus, Class<T> eventType) {
            this.studioEventBus = studioEventBus;
            this.workspaceEventBus = null;
            this.eventType = eventType;
        }

        private Registration(StudioWorkspaceEventBus workspaceEventBus, Class<T> eventType) {
            this.studioEventBus = null;
            this.workspaceEventBus = workspaceEventBus;
            this.eventType = eventType;
        }

        public void handle(Consumer<? super T> consumer) {
            final Consumer<? super T> resolvedConsumer = Objects.requireNonNull(consumer, "consumer");
            if (studioEventBus != null) {
                subscriptions.add(studioEventBus.subscribe(eventType, resolvedConsumer));
                return;
            }
            subscriptions.add(workspaceEventBus.subscribe(eventType, resolvedConsumer));
        }
    }
}
