package com.izouma.nineth.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alipay.mychain.sdk.api.utils.Utils;
import com.alipay.mychain.sdk.domain.transaction.LogEntry;
import com.antfinancial.mychain.baas.tool.restclient.RestClient;
import com.antfinancial.mychain.baas.tool.restclient.RestClientProperties;
import com.antfinancial.mychain.baas.tool.restclient.model.CallRestBizParam;
import com.antfinancial.mychain.baas.tool.restclient.model.Method;
import com.antfinancial.mychain.baas.tool.restclient.model.ReceiptDecoration;
import com.antfinancial.mychain.baas.tool.restclient.response.BaseResp;
import com.izouma.nineth.ApplicationTests;
import com.izouma.nineth.config.GeneralProperties;
import com.izouma.nineth.dto.NFT;
import com.izouma.nineth.utils.HashUtils;
import com.izouma.nineth.utils.SnowflakeIdWorker;
import com.izouma.nineth.utils.TokenUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.File;
import java.math.BigInteger;
import java.util.Scanner;

@Slf4j
public class NFTServiceTest extends ApplicationTests {
    @Autowired
    private NFTService           nftService;
    @Autowired
    private RestClient           restClient;
    @Autowired
    private RestClientProperties restClientProperties;
    @Autowired
    private GeneralProperties    generalProperties;
    @Autowired
    private SnowflakeIdWorker    snowflakeIdWorker;

    @Test
    public void createAccount() {
        nftService.createAccount(RandomStringUtils.randomAlphabetic(8));
    }

    @Test
    public void createToken() throws Exception {
        JSONArray jsonArray = new JSONArray();
        jsonArray.add(Utils.getIdentityByName("raex_official"));

        String s = TokenUtils.genTokenId();

        jsonArray.add(new BigInteger(s, 16).toString());
        log.info("data {}", jsonArray.toJSONString());
        CallRestBizParam callRestBizParam = CallRestBizParam.builder()
                .orderId(String.valueOf(snowflakeIdWorker.nextId()))
                .bizid(restClientProperties.getBizid())
                .account(restClientProperties.getAccount())
                .contractName(generalProperties.getContractName())
                .methodSignature("mint(identity,uint256)")
                .inputParamListStr(jsonArray.toJSONString())
                .outTypes("[]")//合约返回值类型
                .mykmsKeyId(restClientProperties.getKmsId())
                .method(Method.CALLCONTRACTBIZASYNC)
                .tenantid(restClientProperties.getTenantid())
                .gas(500000L)
                .build();
        BaseResp resp = restClient.bizChainCallWithReceipt(callRestBizParam);
        if (!resp.isSuccess()) {
            log.info("EVM合约执行失败: " + resp.getCode() + ", " + resp.getData());
        }
        if ("200".equals(resp.getCode())) {
            log.info("EVM合约执行成功");
            // 合约调用交易回执内容
            ReceiptDecoration txReceipt = JSON.parseObject(resp.getData(), ReceiptDecoration.class);
            BigInteger gasUsed = txReceipt.getGasUsed();
            long result = txReceipt.getResult();
            log.info("EVM合约交易内容: 哈希 " + txReceipt.getHash() + ", 消耗燃料 " + gasUsed + ", 结果 " + result);
            for (LogEntry logEntry : txReceipt.getLogs()) {
                if (logEntry.getTopics().get(0).equals(HashUtils.Keccak256("Transfer(identity,identity,uint256)"))) {
                    String tokenId = logEntry.getTopics().get(3);
                    txReceipt.getBlockNumber();
                    NFT nft = new NFT(txReceipt.getHash(), tokenId, txReceipt.getBlockNumber(), txReceipt.getGasUsed());
                    log.info("NFT生成成功 {}", nft);
                }
            }
        } else {
            // 异步交易未成功需要根据状态码判断交易状态
            log.error("EVM合约执行未成功: " + resp.getCode());
        }
    }

    @Test
    public void testCreateToken() {
    }

    @Test
    public void transferToken() throws Exception {
        nftService.transferToken("000000000000000000000000000000000000000000000000000000000000009d",
                "9th_BHlKkGWw", "9th_test");
    }

    @Test
    public void setApprovalForAll() throws Exception {
        nftService.setApprovalForAll("9th_test");
    }

    @Test
    public void deployContract() throws Exception {
        ProcessBuilder builder = new ProcessBuilder("/Users/drew/Projects/Java/9th/src/main/contract/mychain_solc", "--bin", "9th.sol");
        builder.directory(new File("/Users/drew/Projects/Java/9th/src/main/contract").getAbsoluteFile());

        Process process = builder.start();

        Scanner s = new Scanner(process.getInputStream());
        StringBuilder text = new StringBuilder();
        while (s.hasNextLine()) {
            text.append(s.nextLine());
            text.append("\n");
        }
        s.close();

        int result = process.waitFor();

        String[] lines = text.toString().split("\n");
        int idx = 0;
        for (int i = 0; i < lines.length; i++) {
            if ("======= 9th.sol:ERC721PresetMinterPauserAutoId =======".equals(lines[i])) {
                idx = i;
                break;
            }
        }
        System.out.println(lines[idx]);
        System.out.println(lines[idx + 2]);


        nftService.deployContract("nine_space_test" + System.currentTimeMillis(), lines[idx + 2]);
    }

    @Test
    public void ownerof() throws Exception {
        CallRestBizParam callRestBizParam = CallRestBizParam.builder()
                .orderId(String.valueOf(snowflakeIdWorker.nextId()))
                .bizid(restClientProperties.getBizid())
                .account(restClientProperties.getAccount())
                .contractName("raex12")
                .methodSignature("ownerOf(uint256)")
                .inputParamListStr("[\"95057808871064671354760012409081314299\"]")
                .outTypes("[identity]")//合约返回值类型
                .mykmsKeyId(restClientProperties.getKmsId())
                .method(Method.CALLCONTRACTBIZASYNC)
                .tenantid(restClientProperties.getTenantid())
                .gas(500000L)
                .build();
        BaseResp resp = restClient.bizChainCallWithReceipt(callRestBizParam);
        if (!resp.isSuccess()) {
            log.info("EVM合约执行失败: " + resp.getCode() + ", " + resp.getData());
        }
        if ("200".equals(resp.getCode())) {
            log.info("EVM合约执行成功");
            // 合约调用交易回执内容
            ReceiptDecoration txReceipt = JSON.parseObject(resp.getData(), ReceiptDecoration.class);
            BigInteger gasUsed = txReceipt.getGasUsed();
            long result = txReceipt.getResult();
            log.info("EVM合约交易内容: 哈希 " + txReceipt.getHash() + ", 消耗燃料 " + gasUsed + ", 结果 " + result);
            log.info("owner:{}", Hex.encodeHexString(txReceipt.getOutput()));
            for (LogEntry logEntry : txReceipt.getLogs()) {
                if (logEntry.getTopics().get(0).equals(HashUtils.Keccak256("Transfer(identity,identity,uint256)"))) {
                    String tokenId = logEntry.getTopics().get(3);
                    txReceipt.getBlockNumber();
                    NFT nft = new NFT(txReceipt.getHash(), tokenId, txReceipt.getBlockNumber(), txReceipt.getGasUsed());
                    log.info("NFT生成成功 {}", nft);
                }
            }
        } else {
            // 异步交易未成功需要根据状态码判断交易状态
            log.error("EVM合约执行未成功: " + resp.getCode());
        }
    }

    @Test
    public void transfer() throws Exception {
        JSONArray jsonArray = new JSONArray();
        jsonArray.add(Utils.getIdentityByName("raex_official"));
        jsonArray.add(Utils.getIdentityByName("9th_HCWWflAZ_"));
        jsonArray.add("95057808871064671354760012409081314299");
        CallRestBizParam callRestBizParam = CallRestBizParam.builder()
                .orderId(String.valueOf(snowflakeIdWorker.nextId()))
                .bizid(restClientProperties.getBizid())
                .account(restClientProperties.getAccount())
                .contractName("raex12")
                .methodSignature("ownerTransfer(identity,identity,uint256)")
                .inputParamListStr(jsonArray.toJSONString())
                .outTypes("[]")//合约返回值类型
                .mykmsKeyId(restClientProperties.getKmsId())
                .method(Method.CALLCONTRACTBIZASYNC)
                .tenantid(restClientProperties.getTenantid())
                .gas(500000L)
                .build();
        BaseResp resp = restClient.bizChainCallWithReceipt(callRestBizParam);
        if (!resp.isSuccess()) {
            log.info("EVM合约执行失败: " + resp.getCode() + ", " + resp.getData());
        }
        if ("200".equals(resp.getCode())) {
            log.info("EVM合约执行成功");
            // 合约调用交易回执内容
            ReceiptDecoration txReceipt = JSON.parseObject(resp.getData(), ReceiptDecoration.class);
            BigInteger gasUsed = txReceipt.getGasUsed();
            long result = txReceipt.getResult();
            log.info("EVM合约交易内容: 哈希 " + txReceipt.getHash() + ", 消耗燃料 " + gasUsed + ", 结果 " + result);
            log.info("owner:{}", Hex.encodeHexString(txReceipt.getOutput()));
            for (LogEntry logEntry : txReceipt.getLogs()) {
                if (logEntry.getTopics().get(0).equals(HashUtils.Keccak256("Transfer(identity,identity,uint256)"))) {
                    String tokenId = logEntry.getTopics().get(3);
                    txReceipt.getBlockNumber();
                    NFT nft = new NFT(txReceipt.getHash(), tokenId, txReceipt.getBlockNumber(), txReceipt.getGasUsed());
                    log.info("NFT生成成功 {}", nft);
                }
            }
        } else {
            // 异步交易未成功需要根据状态码判断交易状态
            log.error("EVM合约执行未成功: " + resp.getCode());
        }
    }
}