package io.papermc.paper.plugin.storage;

import io.papermc.paper.plugin.entrypoint.strategy.PluginGraphCycleException;
import io.papermc.paper.plugin.entrypoint.strategy.ProviderLoadingStrategy;
import io.papermc.paper.plugin.provider.PluginProvider;

import java.util.ArrayList;
import java.util.List;

public abstract class SimpleProviderStorage<T> implements ProviderStorage<T> {

    protected final List<PluginProvider<T>> providers = new ArrayList<>();
    protected ProviderLoadingStrategy<T> strategy;

    protected SimpleProviderStorage(ProviderLoadingStrategy<T> strategy) {
        this.strategy = strategy;
    }

    @Override
    public void register(PluginProvider<T> provider) {
        this.providers.add(provider);
    }

    @Override
    public void enter() {
        List<PluginProvider<T>> providerList = new ArrayList<>(this.providers);
        this.filterLoadingProviders(providerList);

        try {
            for (T plugin : this.strategy.loadProviders(providerList)) {
                this.processProvided(plugin);
            }
        } catch (PluginGraphCycleException exception) {
            this.handleCycle(exception);
        }
    }

    @Override
    public Iterable<PluginProvider<T>> getRegisteredProviders() {
        return this.providers;
    }

    public void processProvided(T provided) {}

    // Mutable enter
    protected void filterLoadingProviders(List<PluginProvider<T>> providers) {}

    protected abstract void handleCycle(PluginGraphCycleException exception);

    @Override
    public String toString() {
        return "SimpleProviderStorage{" +
            "providers=" + this.providers +
            ", strategy=" + this.strategy +
            '}';
    }
}
