package servers;

import blockchain.data.BCS;
import io.grpc.stub.StreamObserver;
import proto.crpcs.clientService.ClientServiceGrpc.*;
import proto.types.block.*;
import proto.types.transaction.*;
import proto.types.client.*;
import proto.types.utils;
import utils.customException.ClientException;
import static java.lang.String.format;
import static utils.config.Config.*;

public class ClientRpcsService extends ClientServiceImplBase {
    private final static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(ClientRpcsService.class);

//    private Top topServer;

//    ClientRpcsService(Top topServer)  {
//        this.topServer = topServer;
//    }

    @Override
    public void writeTx(Transaction request,
                      StreamObserver<TxID> responseObserver) {
        logger.debug(format("received txWrite request from [%d]", request.getClientID()));
        TxID tid = Top.addTransaction(request);
        responseObserver.onNext(tid);
        responseObserver.onCompleted();
    }

    @Override
    public void readTx(TxReq request,
                     StreamObserver<Transaction> responseObserver) {
        logger.debug(format("received read request from [%d]", request.getCid()));
        try {
            Transaction tx = Top.getTransaction(request.getTid(), request.getBlocking());
            responseObserver.onNext(tx);
        } catch (InterruptedException e) {
            logger.error(e);
            responseObserver.onError(new ClientException("Server was interrupted while handling the request"));
        } finally {
            responseObserver.onCompleted();
        }

    }

    @Override
    public void txStatus(TxReq request,
                      StreamObserver<TxStatus> responseObserver) {
        logger.debug(format("received status request from [%d]", request.getCid()));
        try {
            TxState sts = Top.status(request.getTid(), request.getBlocking());
            responseObserver.onNext(TxStatus.newBuilder().setStatus(sts).build());
        } catch (InterruptedException e) {
            logger.error(e);
            responseObserver.onError(new ClientException("Server was interrupted while handling the request"));
        } finally {
            responseObserver.onCompleted();
        }


    }

    @Override
    public void readBlock(BlockReq request,
                          StreamObserver<Block> responseObserver) {
        try {
            Block b = Top.deliver(request.getHeight(), request.getBlocking());
            responseObserver.onNext(b);
        } catch (InterruptedException e) {
            logger.error(e);
            responseObserver.onError(new ClientException("Server was interrupted while handling the request"));
        } finally {
            responseObserver.onCompleted();
        }
    }

    @Override
    public void isAlive(utils.Empty request,
                        StreamObserver<utils.Empty> responseObserver) {
        responseObserver.onNext(utils.Empty.newBuilder().build());
        responseObserver.onCompleted();
    }

    @Override
    public void poolSize(utils.Empty request,
                         StreamObserver<utils.Integer> responseObserver) {
        responseObserver.onNext(utils.Integer.newBuilder().setNum(Top.poolSize()).build());
        responseObserver.onCompleted();
    }

    @Override
    public void getHeight(utils.Empty request,
                         StreamObserver<utils.Integer> responseObserver) {
        responseObserver.onNext(utils.Integer.newBuilder().setNum(BCS.height()).build());
        responseObserver.onCompleted();
    }

    @Override
    public void pendingSize(utils.Empty request,
                         StreamObserver<utils.Integer> responseObserver) {
        responseObserver.onNext(utils.Integer.newBuilder().setNum(Top.pendingSize()).build());
        responseObserver.onCompleted();
    }

    @Override
    public void getValidators(utils.Empty request,
                            StreamObserver<Validators> responseObserver) {
        Validators.Builder v = Validators.newBuilder();
        for (int i = 0 ; i < getC() ; i++) {
            v.addIps(getIP(i));
        }
        responseObserver.onNext(v.build());
        responseObserver.onCompleted();
    }

    @Override
    public void getConfigInfo(utils.Empty request,
                              StreamObserver<ConfigInfo> responseObserver) {
        responseObserver.onNext(ConfigInfo.newBuilder()
                .setClusterSize(getN())
                .setMaxFailures(getF())
                .setServerID(Top.getID())
                .setWorkers(getC())
                .setInitTmo(getTMO())
                .setMaxTxInBlock(getMaxTransactionsInBlock())
                .build());
        responseObserver.onCompleted();
    }


}
