package util;

import com.alibaba.fastjson.JSONObject;
import config.Config;
import exception.ZXChainSDKException;
import org.apache.commons.lang3.StringUtils;
import util.model.CreatePriAndPubKeyResp;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Base64;
import java.util.Objects;
import java.util.UUID;

public class ZxlSDKUtil {
    public static JSONObject generateApiSign() throws Exception {
        JSONObject param = new JSONObject();
        //方案一需要传appId和appKey
        param.put("secretId", Config.secretId);
        param.put("secretKey", Config.secretKey);

        String responseStr = HttpUtil.postJsonX(Config.walletSDKHost + "/generateApiSign", param, null);
        JSONObject response = JSONObject.parseObject(responseStr);
        String err = response.get("err").toString();
        if (StringUtils.isNotBlank(err)) {
            throw new ZXChainSDKException("generateApiSign调用失败：" + err);
        }

        JSONObject header = JSONObject.parseObject(response.get("signData").toString());
        header.put("Signature-Time", header.remove("SignatureTime"));
        header.put("Secret-Id", Config.secretId);
        String traceId = UUID.randomUUID().toString();
        //建议请求头中加入Cloud-Trace-Id，出问题方便全链路追踪
        header.put("Cloud-Trace-Id", traceId);
        //todo 打印在日志中，方便出问题时全链路追踪
        System.out.println("Cloud-Trace-Id:"+traceId);

        return header;
    }

    //生成助记词
    public static String createMnemonic() throws Exception {
        String responseStr = HttpUtil.postJsonX(Config.walletSDKHost + "/createMnemonic", null, null);
        JSONObject response = JSONObject.parseObject(responseStr);
        String err = response.get("err").toString();
        if (StringUtils.isNotBlank(err)) {
            throw new ZXChainSDKException("createMnemonic调用失败：" + err);
        }
        return response.get("mnemonic").toString();
    }

    //派生生成公私钥对
    public static CreatePriAndPubKeyResp deriveKeyPair(String mnemonic, int index) throws Exception {
        JSONObject param = new JSONObject();
        param.put("mnemonic", mnemonic);
        param.put("index", index);
        String responseStr = HttpUtil.postJsonX(Config.walletSDKHost + "/deriveKeyPair", param, null);
        CreatePriAndPubKeyResp resp = Tools.toJavaClass(responseStr, CreatePriAndPubKeyResp.class);
        if (StringUtils.isNotBlank(resp.getErr())) {
            throw new ZXChainSDKException("deriveKeyPair调用失败：" + resp.getErr());
        }
        return resp;
    }

    //私钥生成对应公钥
    public static String priKey2PubKey(String priKey) throws Exception {
        JSONObject param = new JSONObject();
        param.put("pri", priKey);
        String responseStr = HttpUtil.postJsonX(Config.walletSDKHost + "/priKey2PubKey", param, null);
        JSONObject response = JSONObject.parseObject(responseStr);
        String err = response.get("err").toString();
        if (StringUtils.isNotBlank(err)) {
            throw new ZXChainSDKException("priKey2PubKey调用失败：" + err);
        }

        return response.get("pub").toString();
    }

    //公钥生成对应地址
    public static String pubKey2Address(String pubKey) throws Exception {
        JSONObject param = new JSONObject();
        param.put("pubKey", pubKey);
        String responseStr = HttpUtil.postJsonX(Config.walletSDKHost + "/pubKey2Address", param, null);
        JSONObject response = JSONObject.parseObject(responseStr);
        String err = response.get("err").toString();
        if (StringUtils.isNotBlank(err)) {
            throw new ZXChainSDKException("pubKey2Address调用失败：" + err);
        }

        return response.get("address").toString();
    }

    //私钥生成对应地址
    public static String priKey2Address(String priKey) throws Exception {
        JSONObject param = new JSONObject();
        param.put("priKey", priKey);
        String responseStr = HttpUtil.postJsonX(Config.walletSDKHost + "/priKey2Address", param, null);
        JSONObject response = JSONObject.parseObject(responseStr);
        String err = response.get("err").toString();
        if (StringUtils.isNotBlank(err)) {
            throw new ZXChainSDKException("priKey2Address调用失败：" + err);
        }

        return response.get("address").toString();
    }

    //私钥签名
    public static String signByPriKey(String priKey, String data) throws Exception{
        JSONObject param = new JSONObject();
        param.put("priKey", priKey);
        param.put("data", data);
        String responseStr = HttpUtil.postJsonX(Config.walletSDKHost + "/signByPriKey", param, null);
        JSONObject response = JSONObject.parseObject(responseStr);
        String err = response.get("err").toString();
        if (StringUtils.isNotBlank(err)) {
            throw new ZXChainSDKException("signByPriKey调用失败：" + err);
        }
        return response.get("signedData").toString();
    }

    //验签
    public static boolean verifyByPubKey(String pubKey, String signedData, String data) throws Exception{
        JSONObject param = new JSONObject();
        param.put("pubKey", pubKey);
        param.put("data", data);
        param.put("signedData", signedData);
        String responseStr = HttpUtil.postJsonX(Config.walletSDKHost + "/verifyByPubKey", param, null);
        JSONObject response = JSONObject.parseObject(responseStr);
        String err = response.get("err").toString();
        if (StringUtils.isNotBlank(err)) {
            throw new ZXChainSDKException("verifyByPubKey调用失败：" + err);
        }

        return StringUtils.compare("true", response.get("isValid").toString()) == 0;
    }

    //sm3哈希
    public static String sm3Hash(String data) throws Exception {
        JSONObject param = new JSONObject();
        String req = Base64.getEncoder().encodeToString(data.getBytes(StandardCharsets.UTF_8));
        param.put("data", req);
        String responseStr = HttpUtil.postJsonX(Config.walletSDKHost + "/sm3Hash", param, null);
        JSONObject response = JSONObject.parseObject(responseStr);
        String err = response.get("err").toString();
        if (StringUtils.isNotBlank(err)) {
            throw new ZXChainSDKException("sm3Hash调用失败：" + err);
        }
        return response.get("digest").toString();
    }

    //sm3哈希
    public static String sm3Hash(byte[] data) throws Exception {
        JSONObject param = new JSONObject();
        String req = Base64.getEncoder().encodeToString(data);
        param.put("data", req);
        String responseStr = HttpUtil.postJsonX(Config.walletSDKHost + "/sm3Hash", param, null);
        JSONObject response = JSONObject.parseObject(responseStr);
        String err = response.get("err").toString();
        if (StringUtils.isNotBlank(err)) {
            throw new ZXChainSDKException("sm3Hash调用失败：" + err);
        }

        return response.get("digest").toString();
    }

    // sdk-上传cos
    public static void uploadToCos(String cosPath, String tempSecretId, String tempSecretKey,
                                   String sessionToken, String filePath) throws Exception {
        Path tempFilePath = null;
        try {
            String path;
            File file = new File(filePath);
            if (!file.exists()) {
                byte[] bytesFile = Tools.getNetworkFiles(filePath);
                // 生成临时文件名
                int extensionIndex = filePath.lastIndexOf(".");
                String extension = extensionIndex != -1 ? filePath.substring(extensionIndex + 1).toLowerCase() : "";
                String tempFileName = String.format("%s_%s.%s", "temp_file_", UUID.randomUUID(), extension);
                tempFilePath = Paths.get(".", tempFileName);
                // 创建并写入数据到临时文件
                Files.write(tempFilePath, bytesFile, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
                path = tempFilePath.toAbsolutePath().toString();
            } else {
                path = filePath;
            }

            JSONObject param = new JSONObject();
            param.put("cosPath", cosPath);
            param.put("tempSecretId", tempSecretId);
            param.put("tempSecretKey", tempSecretKey);
            param.put("sessionToken", sessionToken);
            param.put("filePath", path);

            //todo 存储文件地址
            System.out.println(cosPath);

            String responseStr = HttpUtil.postJsonX(Config.walletSDKHost + "/uploadToCos", param, null);
            JSONObject response = JSONObject.parseObject(responseStr);
            String err = response.get("err").toString();
            if (StringUtils.isNotBlank(err)) {
                throw new ZXChainSDKException("uploadToCos调用失败：" + err);
            }
        } finally {
            // 在实际应用中，记得在使用完临时文件后删除它
            if (Objects.nonNull(tempFilePath)) {
                Files.delete(tempFilePath);
            }
        }
    }
}
