package com.atlassian.bitbucket.mesh.auth;

import com.atlassian.bitbucket.mesh.util.BuilderSupport;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;

import javax.annotation.Nonnull;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import static java.util.Objects.requireNonNull;

public class UpdatePublicKeysParameters {

    private final boolean complete;
    private final Set<ExpirablePublicKey> controlPlaneKeys;
    private final Map<String, Set<ExpirablePublicKey>> keysByNode;
    private final Set<ExpirablePublicKey> sidecarKeys;

    private UpdatePublicKeysParameters(Builder builder) {
        complete = builder.complete;
        controlPlaneKeys = ImmutableSet.copyOf(builder.controlPlaneKeys);
        keysByNode = ImmutableMap.copyOf(Maps.transformValues(builder.keysByNode, ImmutableSet::copyOf));
        sidecarKeys = ImmutableSet.copyOf(builder.sidecarKeys);
    }

    @Nonnull
    public Set<ExpirablePublicKey> getControlPlaneKeys() {
        return controlPlaneKeys;
    }

    @Nonnull
    public Map<String, Set<ExpirablePublicKey>> getKeysByNode() {
        return keysByNode;
    }

    @Nonnull
    public Set<ExpirablePublicKey> getSidecarKeys() {
        return sidecarKeys;
    }

    public boolean isComplete() {
        return complete;
    }

    public static class Builder extends BuilderSupport {

        private final Set<ExpirablePublicKey> controlPlaneKeys;
        private final Map<String, Set<ExpirablePublicKey>> keysByNode;
        private final Set<ExpirablePublicKey> sidecarKeys;

        private boolean complete;

        public Builder() {
            controlPlaneKeys = new HashSet<>();
            keysByNode = new HashMap<>();
            sidecarKeys = new HashSet<>();
        }

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

        @Nonnull
        public Builder complete(boolean value) {
            complete = value;

            return this;
        }

        @Nonnull
        public Builder controlPlaneKey(@Nonnull ExpirablePublicKey value) {
            controlPlaneKeys.add(requireNonNull(value, "controlPlaneKey"));

            return this;
        }

        @Nonnull
        public Builder nodeKey(@Nonnull String nodeId, @Nonnull ExpirablePublicKey nodeKey) {
            requireNonBlank(nodeId, "nodeId");
            requireNonNull(nodeKey, "nodeKey");

            keysByNode.computeIfAbsent(nodeId, ignored -> new HashSet<>())
                    .add(nodeKey);

            return this;
        }

        @Nonnull
        public Builder sidecarKey(@Nonnull ExpirablePublicKey value) {
            sidecarKeys.add(requireNonNull(value, "sidecarKey"));

            return this;
        }
    }
}
