package com.atlassian.bitbucket.mesh.repair;

import com.atlassian.bitbucket.mesh.repository.ReplicaState;
import com.atlassian.bitbucket.mesh.rpc.v1.RpcRepairSummary;
import com.google.protobuf.Timestamp;

import javax.annotation.Nonnull;
import java.time.Instant;

import static java.util.Objects.requireNonNull;

/**
 * The result of a repository replica repair operation.
 */
public class RepairSummary {

    private final ReplicaState sourceState;
    private final ReplicaState targetState;
    private final Instant timestamp;
    private final long version;

    public RepairSummary(@Nonnull Instant timestamp, @Nonnull ReplicaState sourceState,
                         @Nonnull ReplicaState targetState, long version) {
        this.sourceState = requireNonNull(sourceState, "sourceState");
        this.targetState = requireNonNull(targetState, "targetState");
        this.timestamp = requireNonNull(timestamp, "timestamp");
        this.version = version;
    }

    @Nonnull
    public static RepairSummary fromRepairSummary(@Nonnull RpcRepairSummary summary) {
        requireNonNull(summary, "summary");
        Timestamp timestamp = summary.getTimestamp();
        return new RepairSummary(Instant.ofEpochSecond(timestamp.getSeconds(), timestamp.getNanos()),
                ReplicaState.fromRpc(summary.getSourceState()),
                ReplicaState.fromRpc(summary.getTargetState()),
                summary.getVersion());
    }

    /**
     * @return the state of replica on the repair source node at {@link #getTimestamp()}
     */
    @Nonnull
    public ReplicaState getSourceState() {
        return sourceState;
    }

    /**
     * @return the state of replica on the repair target node at {@link #getTimestamp()}
     */
    @Nonnull
    public ReplicaState getTargetState() {
        return targetState;
    }

    /**
     * @return the timestamp at which the source and target states were observed
     */
    @Nonnull
    public Instant getTimestamp() {
        return timestamp;
    }

    /**
     * @return the version that was observed on the source and that the target is
     *         {@link #getTargetState() (in)consistent} with
     */
    public long getVersion() {
        return version;
    }

    @Nonnull
    public RpcRepairSummary toRepairSummary() {
        return RpcRepairSummary.newBuilder()
                .setSourceState(sourceState.toRpc())
                .setTargetState(targetState.toRpc())
                .setTimestamp(Timestamp.newBuilder()
                        .setSeconds(timestamp.getEpochSecond())
                        .setNanos(timestamp.getNano()))
                .setVersion(version)
                .build();
    }
}
