package com.atlassian.bitbucket.mesh.management;

import com.atlassian.bitbucket.mesh.auth.UpdatePublicKeysParameters;
import com.atlassian.bitbucket.mesh.network.UpdateTopologyParameters;
import com.atlassian.bitbucket.mesh.util.BuilderSupport;
import com.google.common.collect.ImmutableMap;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Map;

import static java.util.Objects.requireNonNull;

public class UpdateConfigurationParameters {

    private final boolean fromControlPlane;
    private final Map<String, Long> inconsistentReplicas;
    private final Map<String, String> properties;
    private final UpdatePublicKeysParameters publicKeys;
    private final UpdateTopologyParameters topology;

    private UpdateConfigurationParameters(Builder builder) {
        fromControlPlane = builder.fromControlPlane;
        inconsistentReplicas = builder.inconsistentReplicas.build();
        properties = builder.properties == null ? null : builder.properties.build();
        publicKeys = builder.publicKeys;
        topology = builder.topology;
    }

    /**
     * @return a map of repository ID to the repository version the replica is inconsistent with
     */
    @Nonnull
    public Map<String, Long> getInconsistentReplicas() {
        return inconsistentReplicas;
    }

    /**
     * @return the configuration properties to update; {@code null} if configuration properties should not be updated
     */
    @Nullable
    public Map<String, String> getProperties() {
        return properties;
    }

    /**
     * @return public key updates; {@code null} if public keys should not be updated
     */
    @Nullable
    public UpdatePublicKeysParameters getPublicKeys() {
        return publicKeys;
    }

    /**
     * @return the topology updates; {@code null} if the topology should not be updated
     */
    @Nullable
    public UpdateTopologyParameters getTopology() {
        return topology;
    }

    /**
     * @return {@code true} if the configuration request was received from the control plane
     */
    public boolean isFromControlPlane() {
        return fromControlPlane;
    }

    public static class Builder extends BuilderSupport {

        private final ImmutableMap.Builder<String, Long> inconsistentReplicas;

        private boolean fromControlPlane;
        private ImmutableMap.Builder<String, String> properties;
        private UpdatePublicKeysParameters publicKeys;
        private UpdateTopologyParameters topology;

        public Builder() {
            inconsistentReplicas = ImmutableMap.builder();
        }

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

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

        @Nonnull
        public Builder inconsistentReplica(@Nonnull String repositoryId, long version) {
            inconsistentReplicas.put(requireNonBlank(repositoryId, "repositoryId"), version);
            return this;
        }

        @Nonnull
        public Builder properties(@Nonnull Map<String, String> value) {
            propertiesBuilder().putAll(requireNonNull(value, "value"));
            return this;
        }

        @Nonnull
        public Builder property(@Nonnull String key, @Nonnull String value) {
            propertiesBuilder().put(requireNonNull(key, "key"), requireNonNull(value, "value"));
            return this;
        }

        @Nonnull
        public Builder publicKeys(@Nullable UpdatePublicKeysParameters value) {
            publicKeys = value;
            return this;
        }

        @Nonnull
        public Builder topology(@Nullable UpdateTopologyParameters value) {
            topology = value;
            return this;
        }

        private ImmutableMap.Builder<String, String> propertiesBuilder() {
            if (properties == null) {
                properties = ImmutableMap.builder();
            }
            return properties;
        }
    }
}
