package com.atlassian.bitbucket.mesh.git.hook.script;

import com.atlassian.bitbucket.mesh.git.ref.RefUpdate;
import com.atlassian.bitbucket.mesh.repository.Repository;
import com.atlassian.bitbucket.mesh.util.BuilderSupport;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static com.google.common.base.MoreObjects.firstNonNull;
import static java.util.Objects.requireNonNull;

public class CallHookScriptParameters {

    private final boolean abortOnFirstVeto;
    private final Map<String, String> environment;
    private final Duration executionTimeout;
    private final Duration idleTimeout;
    private final List<RefUpdate> refUpdates;
    private final Repository repository;

    private CallHookScriptParameters(Builder builder) {
        abortOnFirstVeto = builder.abortOnFirstVeto;
        environment = builder.environment.build();
        executionTimeout = requireNonNull(builder.executionTimeout, "executionTimeout");
        idleTimeout = firstNonNull(builder.idleTimeout, executionTimeout);
        refUpdates = builder.refUpdates.build();
        repository = builder.repository;
    }

    @Nonnull
    public Repository getRepository() {
        return repository;
    }

    @Nonnull
    public Map<String, String> getEnvironment() {
        return environment;
    }

    @Nonnull
    public Duration getExecutionTimeout() {
        return executionTimeout;
    }

    @Nonnull
    public Duration getIdleTimeout() {
        return idleTimeout;
    }

    @Nonnull
    public List<RefUpdate> getRefUpdates() {
        return refUpdates;
    }

    public boolean isAbortOnFirstVeto() {
        return abortOnFirstVeto;
    }

    public static class Builder extends BuilderSupport {

        private final ImmutableMap.Builder<String, String> environment;
        private final ImmutableList.Builder<RefUpdate> refUpdates;
        private final Repository repository;

        private boolean abortOnFirstVeto;
        private Duration executionTimeout;
        private Duration idleTimeout;

        public Builder(@Nonnull Repository repository) {
            this.repository = requireNonNull(repository, "repository");

            environment = ImmutableMap.builder();
            refUpdates = ImmutableList.builder();
        }

        @Nonnull
        public CallHookScriptParameters build() {
            return new CallHookScriptParameters(this);
        }

        @Nonnull
        public Builder abortOnFirstVeto(boolean value) {
            abortOnFirstVeto = value;
            return this;
        }

        @Nonnull
        public Builder environment(@Nullable Map<String, String> values) {
            if (values != null) {
                values.forEach(this::environment);
            }
            return this;
        }

        @Nonnull
        public Builder environment(@Nullable String key, @Nullable String value) {
            if (key != null && value != null) {
                environment.put(key, value);
            }
            return this;
        }

        @Nonnull
        public Builder executionTimeout(@Nonnull Duration value) {
            executionTimeout = requireNonNull(value, "executionTimeout");
            return this;
        }

        @Nonnull
        public Builder idleTimeout(@Nonnull Duration value) {
            idleTimeout = requireNonNull(value, "idleTimeout");
            return this;
        }

        @Nonnull
        public Builder refUpdates(@Nullable Iterable<RefUpdate> values) {
            addIf(Objects::nonNull, refUpdates, values);
            return this;
        }
    }
}

