package org.implab.gradle.variants.artifacts;

import java.util.Optional;

import org.gradle.api.Action;
import org.gradle.api.InvalidUserDataException;
import org.implab.gradle.variants.core.Variant;

/**
 * Live context for declaring and observing variant outgoing publications.
 *
 * <p>The context becomes available after the core variant model has been finalized.
 * It owns variant-level outgoing declarations, assembly lookup, and hooks for
 * materialized Gradle-facing publication state.
 */
public interface OutgoingVariantsContext {

    /**
     * Returns the assembly lookup service.
     *
     * <p>Assemblies are stateful slot bodies resolved from cheap {@link ArtifactSlot}
     * identities.
     *
     * @return assembly lookup service
     */
    ArtifactAssemblies getAssemblies();

    /**
     * Configures artifact slots of the given variant.
     *
     * @param variant variant identity
     * @param action variant artifact declaration
     */
    void configureVariant(Variant variant, Action<? super VariantArtifactsSpec> action);

    /**
     * Registers a replayable action for declared outgoing variants.
     *
     * <p>The action receives the plugin model object, not necessarily a materialized
     * Gradle publication. Use {@link #whenOutgoingConfiguration(Action)} and
     * {@link #whenOutgoingSlot(Action)} for materialized Gradle-facing state.
     *
     * @param action outgoing variant action
     */
    void configureEach(Action<? super OutgoingVariant> action);

    /**
     * Finds the outgoing model for the given variant.
     *
     * @param variant variant identity
     * @return outgoing model, if declared
     */
    Optional<OutgoingVariant> findOutgoing(Variant variant);

    /**
     * Requires the outgoing model for the given variant.
     *
     * @param variant variant identity
     * @return outgoing model
     * @throws InvalidUserDataException if the outgoing variant is not declared
     */
    default OutgoingVariant requireOutgoing(Variant variant) {
        return findOutgoing(variant)
                .orElseThrow(() -> new InvalidUserDataException("Outgoing variant '" + variant + "' isn't registered"));
    }

    /**
     * Registers a replayable action for materialized variant-level outgoing
     * configurations.
     *
     * @param action materialized outgoing configuration action
     */
    void whenOutgoingConfiguration(Action<? super OutgoingConfigurationSpec> action);

    /**
     * Registers a replayable action for materialized slot publications.
     *
     * <p>Slot publication hooks follow the Gradle outgoing publication model. A
     * declared slot identity by itself does not guarantee that a slot publication has
     * been materialized.
     *
     * @param action materialized slot publication action
     */
    void whenOutgoingSlot(Action<? super OutgoingConfigurationSlotSpec> action);


}
