package org.implab.gradle.variants.artifacts;

import java.util.Optional;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.gradle.api.Action;
import org.gradle.api.InvalidUserDataException;

/**
 * Resolves stateful slot assemblies from cheap slot identities.
 *
 * <p>
 * The returned assembly is a materialized build-model handle. It may expose
 * lazy Gradle providers, but
 * it is no longer an identity object suitable for replayable discovery.
 */
@NonNullByDefault
public interface ArtifactAssemblies {
    /**
     * Resolves the assembly for the given slot.
     *
     * <p>
     * This call materializes the build-facing body of the slot from its identity.
     *
     * @param slot slot identity inside a variant outgoing contract
     * @return assembly handle for the slot
     */
    default ArtifactAssembly require(ArtifactSlot slot) {
        return find(slot)
                .orElseThrow(() -> new InvalidUserDataException("Artifact assembly '" + slot + "' isn't registered"));
    }

    /**
     * Регистрирует обработчик на конкретный слот. Если слот еще не зарегистрирован,
     * то обработчик будет добавлен в очередь и будет вызван при регистрации слота.
     * Порядок и точный момент вызова обработчиков не определен.
     *
     * @param slot   Слот на который нужно зарегистрировать обработчик
     * @param action Обработчик
     */
    void when(ArtifactSlot slot, Action<? super ArtifactAssembly> action);

    /**
     * Регистрирует глобальный обработчик, который будет вызван для всех слотов.
     * Обработчик будет вызван как для уже зарегистрированных слотов так и для тех,
     * которые будут зарегистрированы в будущем.
     *
     * @param action Обработчик
     */
    void all(Action<? super ArtifactAssembly> action);

    /** Ищет зарегистрированный слот */
    Optional<ArtifactAssembly> find(ArtifactSlot slot);
}
