package org.implab.gradle.variants.artifacts.internal;

import java.util.Optional;

import org.gradle.api.Action;
import org.implab.gradle.variants.artifacts.ArtifactAssemblies;
import org.implab.gradle.variants.artifacts.ArtifactAssemblySpec;
import org.implab.gradle.variants.artifacts.ArtifactSlot;
import org.implab.gradle.variants.artifacts.OutgoingConfigurationSlotSpec;
import org.implab.gradle.variants.artifacts.OutgoingConfigurationSpec;
import org.implab.gradle.variants.artifacts.OutgoingVariant;
import org.implab.gradle.variants.artifacts.OutgoingVariantsContext;
import org.implab.gradle.variants.artifacts.VariantArtifactsSpec;
import org.implab.gradle.variants.core.Variant;

public class DefaultOutgoingVariantsContext implements OutgoingVariantsContext {
    private final ArtifactAssemblies assemblies;

    private final ArtifactAssemblyHandler assemblyHandler;

    private final OutgoingRegistry outgoingVariants;

    private final MaterializationPolicyHandler materializationHandler;

    public DefaultOutgoingVariantsContext(
            ArtifactAssemblies assemblies,
            OutgoingRegistry outgoingVariants,
            ArtifactAssemblyHandler assemblyHandler,
            MaterializationPolicyHandler materializationHandler) {
        this.assemblies = assemblies;
        this.outgoingVariants = outgoingVariants;
        this.assemblyHandler = assemblyHandler;
        this.materializationHandler = materializationHandler;
    }

    @Override
    public ArtifactAssemblies getAssemblies() {
        return assemblies;
    }

    @Override
    public void configureVariant(Variant variant, Action<? super VariantArtifactsSpec> action) {
        var outgoingVariant = outgoingVariants.maybeCreate(variant);
        var variantSpec = new VariantSpec(outgoingVariant);
        action.execute(variantSpec);
    }

    @Override
    public void configureEach(Action<? super OutgoingVariant> action) {
        outgoingVariants.configureEach(action::execute);
    }

    @Override
    public Optional<OutgoingVariant> findOutgoing(Variant variant) {
        return outgoingVariants.find(variant);
    }

    @Override
    public void whenOutgoingConfiguration(Action<? super OutgoingConfigurationSpec> action) {
        materializationHandler.whenVariantMaterialized(action);
    }

    @Override
    public void whenOutgoingSlot(Action<? super OutgoingConfigurationSlotSpec> action) {
        materializationHandler.whenSlotMaterialized(action);
    }

    class VariantSpec implements VariantArtifactsSpec {

        private final OutgoingVariant outgoingVariant;

        VariantSpec(OutgoingVariant outgoingVariant) {
            this.outgoingVariant = outgoingVariant;
        }

        @Override
        public void slot(String name, Action<? super ArtifactAssemblySpec> action) {
            var slot = outgoingVariant.getSlots().maybeCreate(name);
            var artifactSlot = new ArtifactSlot(outgoingVariant.getVariant(), slot);
            assemblyHandler.configureAssembly(artifactSlot, action);
        }

        @Override
        public void primarySlot(String name, Action<? super ArtifactAssemblySpec> action) {
            var slot = outgoingVariant.getSlots().maybeCreate(name);
            var artifactSlot = new ArtifactSlot(outgoingVariant.getVariant(), slot);
            assemblyHandler.configureAssembly(artifactSlot, action);

            outgoingVariant.getPrimarySlot().set(slot);
        }

    }

}
