package org.dromara.zjk.config;

import cn.bubi.SDK;
import cn.bubi.common.Tools;
import cn.bubi.model.request.*;
import cn.bubi.model.request.operation.AccountSetMetadataOperation;
import cn.bubi.model.request.operation.BaseOperation;
import cn.bubi.model.response.*;
import cn.bubi.model.response.result.data.Signature;
import cn.bubi.model.response.result.data.TransactionHistory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Slf4j
@Component
public class OnChainUtils {
    private static SDK sdk;
    @Resource
    private YsdpaasConfig ysdpaasConfig;

    //    private static String address = "adxSqD9EdNMNYkfssD28YmSmgE1NLdm18Uhi9";
//    private static String privateKey = "privbynqzw8xmhim7LuwsLbkr4GVzkwn6CasJdbYEhVbFgFEcTWJ9Khq";
    public void toChain(String data, Long reviewId) {
        sdk = SDK.getInstance(ysdpaasConfig.getOnchainUrl());
        Long nonce = getAccountNonce();
        String key = "expert_cq_" + reviewId;
        //String value = "{\"Plaintext\":{},\"Privacy\":{\"userId\":\"\",\"loginName\":\"\",\"phone\":\"\",\"userName\":\"\",\"source\":\"\",\"password\":\"\",\"userType\":\"\",\"isRegisterd\":\"\",\"caHash\":\"\",\"status\":\"\",\"updateTime\":\"\",\"company\":\"\"}}";
        BaseOperation[] operations = buildOperations(ysdpaasConfig.getOnchainAddress(), key, data);

        String tranBlob = seralizeTransaction(nonce, operations);

        Signature[] signatures = signTransaction(tranBlob);

        String txHash = submitTransaction(tranBlob, signatures);
        System.out.println(txHash);

        long startTime = System.currentTimeMillis();
        while (true) {
            long endTime = System.currentTimeMillis();
            if (endTime - startTime > 60000000) {
                log.info("交易执行超时");
                return;
            }
            TransactionHistory transactionHistory = checkTransactionStatus(txHash);
            if (!Tools.isNULL(transactionHistory) && transactionHistory.getErrorCode() == 0) {
                break;
            }
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        log.info("交易结束");
    }

    public long getAccountNonce() {
        long nonce = 0;

        // Init request
        String accountAddress = ysdpaasConfig.getOnchainAddress();
        AccountGetNonceRequest request = new AccountGetNonceRequest();
        request.setAddress(accountAddress);

        // Call getNonce
        AccountGetNonceResponse response = sdk.getAccountService().getNonce(request);
        if (0 == response.getErrorCode()) {
            nonce = response.getResult().getNonce();
        } else {
            System.out.println("error: " + response.getErrorDesc());
        }
        return nonce;
    }

    public static BaseOperation[] buildOperations(String accountAddresss, String key, String value) {
        AccountSetMetadataOperation operation = new AccountSetMetadataOperation();
        operation.setSourceAddress(accountAddresss);
        operation.setKey(key);
        operation.setValue(value);
        BaseOperation[] operations = {operation};
        return operations;
    }

    public String seralizeTransaction(Long nonce, BaseOperation[] operations) {
        String transactionBlob = null;

        // The account address to issue token
        String senderAddress = ysdpaasConfig.getOnchainAddress();  // 创建方账户
        // The gasPrice is fixed at 1000L, the unit is UGas
        Long gasPrice = 1000L;
        // Set up the maximum cost 10000000 UGas
        Long feeLimit = 10000000L;
        // Nonce should add 1
        nonce += 1;

        // Build transaction  Blob
        TransactionBuildBlobRequest transactionBuildBlobRequest = new TransactionBuildBlobRequest();
        transactionBuildBlobRequest.setSourceAddress(senderAddress);
        transactionBuildBlobRequest.setNonce(nonce);
        transactionBuildBlobRequest.setFeeLimit(feeLimit);
        transactionBuildBlobRequest.setGasPrice(gasPrice);
        for (int i = 0; i < operations.length; i++) {
            transactionBuildBlobRequest.addOperation(operations[i]);
        }
        TransactionBuildBlobResponse transactionBuildBlobResponse = sdk.getTransactionService().buildBlob(transactionBuildBlobRequest);
        if (transactionBuildBlobResponse.getErrorCode() == 0) {
            transactionBlob = transactionBuildBlobResponse.getResult().getTransactionBlob();
        } else {
            System.out.println("error: " + transactionBuildBlobResponse.getErrorDesc());
        }
        return transactionBlob;
    }

    public Signature[] signTransaction(String transactionBlob) {
        Signature[] signatures = null;
        // The account private key to issue token
        String senderPrivateKey = ysdpaasConfig.getOnchainKey(); // [创建方账户私钥]

        // Sign transaction Blob
        TransactionSignRequest transactionSignRequest = new TransactionSignRequest();
        transactionSignRequest.setBlob(transactionBlob);
        transactionSignRequest.addPrivateKey(senderPrivateKey);
        TransactionSignResponse transactionSignResponse = sdk.getTransactionService().sign(transactionSignRequest);
        if (transactionSignResponse.getErrorCode() == 0) {
            signatures = transactionSignResponse.getResult().getSignatures();
        } else {
            System.out.println("error: " + transactionSignResponse.getErrorDesc());
        }
        return signatures;
    }

    public static String submitTransaction(String transactionBlob, Signature[] signatures) {
        String hash = null;

        // Submit transaction
        TransactionSubmitRequest transactionSubmitRequest = new TransactionSubmitRequest();
        transactionSubmitRequest.setTransactionBlob(transactionBlob);
        transactionSubmitRequest.setSignatures(signatures);
        TransactionSubmitResponse transactionSubmitResponse = sdk.getTransactionService().submit(transactionSubmitRequest);
        if (0 == transactionSubmitResponse.getErrorCode()) {
            hash = transactionSubmitResponse.getResult().getHash();
        } else {
            System.out.println("error: " + transactionSubmitResponse.getErrorDesc());
        }
        return hash;
    }

    public static TransactionHistory checkTransactionStatus(String txHash) {
        // Init request
        TransactionGetInfoRequest request = new TransactionGetInfoRequest();
        request.setHash(txHash);

        // Call getInfo
        TransactionGetInfoResponse response = sdk.getTransactionService().getInfo(request);
        int errorCode = response.getErrorCode();
        TransactionHistory transactionHistory = null;
        if (errorCode == 0) {
            transactionHistory = response.getResult().getTransactions()[0];
        }

        return transactionHistory;
    }
}
