package com.atlassian.bitbucket.mesh.client;

import com.atlassian.bitbucket.mesh.grpc.AbstractFutureResponseObserver;
import com.atlassian.bitbucket.mesh.network.ConnectivitySummary;
import com.atlassian.bitbucket.mesh.network.MeshNode;
import com.atlassian.bitbucket.mesh.rpc.v1.RpcHeartbeat;
import io.grpc.Status;
import io.grpc.stub.ClientCallStreamObserver;

/**
 * {@link io.grpc.stub.StreamObserver} used to process the response of {@code ManagementService/DiagnoseConnection} for
 * population in the connectivity summary.
 *
 * @see GrpcMeshClient#ping(MeshNode)
 */
class ConnectivitySummaryResponseObserver
        extends AbstractFutureResponseObserver<RpcHeartbeat, RpcHeartbeat, ConnectivitySummary> {

    private String errorMessage;
    private boolean reachable;
    private long start;
    private Status.Code statusCode;

    ConnectivitySummaryResponseObserver() {
    }

    @Override
    public void beforeStart(ClientCallStreamObserver<RpcHeartbeat> requestStream) {
        start = System.currentTimeMillis();
        super.beforeStart(requestStream);
    }

    @Override
    public void onCompleted() {
        setResult(new ConnectivitySummary(reachable, errorMessage, statusCode, System.currentTimeMillis() - start));
        super.onCompleted();
    }

    @Override
    public void onError(Throwable t) {
        if (t.getCause() != null) {
            errorMessage = t.getCause().getMessage();
        } else {
            errorMessage = t.getMessage();
        }
        statusCode = Status.fromThrowable(t).getCode();

        //Even if we get an error, we want the future to complete normally and encode
        //the error result in the ConnectivitySummary. Therefore, we call onCompleted here
        //instead of super.onError
        onCompleted();
    }

    @Override
    public void onNext(RpcHeartbeat rpcHeartbeat) {
        reachable = true;
    }
}
