package com.atlassian.bitbucket.mesh.repository;

import com.atlassian.bitbucket.mesh.rpc.v1.RpcRepositoryReplicaDetails;

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

import static java.util.Objects.requireNonNull;

public class RepositoryReplicaDetails {

    private final String contentHash;
    private final String metadataHash;
    private final long observedVersion;
    private final ReplicaState replicaState;
    private final long version;

    private RepositoryReplicaDetails(Builder builder) {
        contentHash = builder.contentHash;
        metadataHash = builder.metadataHash;
        observedVersion = builder.observedVersion;
        replicaState = builder.replicaState;
        version = builder.version;
    }

    @Nonnull
    public static RepositoryReplicaDetails fromRpc(@Nonnull RpcRepositoryReplicaDetails value) {
        requireNonNull(value, "rpc");
        RepositoryReplicaDetails.Builder builder = new Builder(ReplicaState.fromRpc(value.getReplicaState()))
                .observedVersion(value.getObservedVersion())
                .version(value.getVersion());
        if (value.hasContentHash()) {
            builder.contentHash(value.getContentHash());
        }
        if (value.hasMetadataHash()) {
            builder.metadataHash(value.getMetadataHash());
        }
        return builder.build();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        RepositoryReplicaDetails that = (RepositoryReplicaDetails) o;
        return observedVersion == that.observedVersion &&
                version == that.version &&
                Objects.equals(contentHash, that.contentHash) &&
                Objects.equals(metadataHash, that.metadataHash) &&
                replicaState == that.replicaState;
    }

    @Nullable
    public String getContentHash() {
        return contentHash;
    }

    @Nullable
    public String getMetadataHash() {
        return metadataHash;
    }

    public long getObservedVersion() {
        return observedVersion;
    }

    @Nonnull
    public ReplicaState getReplicaState() {
        return replicaState;
    }

    public long getVersion() {
        return version;
    }

    @Override
    public int hashCode() {
        return Objects.hash(contentHash, metadataHash, observedVersion, replicaState, version);
    }

    @Nonnull
    public RpcRepositoryReplicaDetails toRpc() {
        RpcRepositoryReplicaDetails.Builder builder = RpcRepositoryReplicaDetails.newBuilder()
                .setReplicaState(replicaState.toRpc());
        if (contentHash != null) {
            builder.setContentHash(contentHash);
        }
        if (metadataHash != null) {
            builder.setMetadataHash(metadataHash);
        }
        if (observedVersion > 0L) {
            builder.setObservedVersion(observedVersion);
        }
        if (version > 0L) {
            builder.setVersion(version);
        }
        return builder.build();
    }

    public static class Builder {

        private final ReplicaState replicaState;

        private String contentHash;
        private String metadataHash;
        private long observedVersion;
        private long version;

        @Nonnull
        public Builder(@Nonnull ReplicaState replicaState) {
            this.replicaState = requireNonNull(replicaState, "replicaState");
        }

        @Nonnull
        public Builder(@Nonnull RepositoryReplicaDetails other) {
            requireNonNull(other, "other");

            contentHash = other.contentHash;
            metadataHash = other.metadataHash;
            observedVersion = other.observedVersion;
            replicaState = other.replicaState;
            version = other.version;
        }

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

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

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

        @Nonnull
        public Builder observedVersion(long value) {
            observedVersion = value;
            return this;
        }

        @Nonnull
        public Builder version(long value) {
            version = value;
            return this;
        }
    }
}
