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"));
    }

    /**
     * Registers a configuration action for the assembly of the given slot.
     *
     * <p>If the assembly is already registered, the action is invoked immediately.
     * Otherwise, it is queued and invoked when slot materialization registers the
     * assembly handle.
     *
     * @param slot slot identity inside a variant outgoing contract
     * @param action assembly configuration action
     */
    void when(ArtifactSlot slot, Action<? super ArtifactAssembly> action);

    /**
     * Adds global configuration action for all materialized assemblies. If some assemblies are
     * already registered, the action will be invoked for them immediately. For assemblies that
     * are materialized later, the action will be invoked when they are registered.
     *
     * @param action assembly configuration action.
     */
    void configureEach(Action<? super ArtifactAssembly> action);

    /**
     * Finds a registered assembly for the given slot identity.
     *
     * @param slot slot identity inside a variant outgoing contract
     * @return registered assembly, if the slot body has already been materialized
     */
    Optional<ArtifactAssembly> find(ArtifactSlot slot);
}
