package org.bdware.sc.boundry.utils;

import org.bdware.sc.compiler.PermissionStub;
import org.bdware.sc.node.Permission;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.zz.gmhelper.BCECUtil;
import org.zz.gmhelper.SM2KeyPair;
import wrp.jdk.nashorn.api.scripting.ScriptObjectMirror;
import wrp.jdk.nashorn.internal.runtime.PropertyMap;
import wrp.jdk.nashorn.internal.runtime.ScriptObject;
import wrp.jdk.nashorn.internal.scripts.JO;

import java.math.BigInteger;

@PermissionStub(permission = Permission.SM2)
public class SM2Util {

    public static ScriptObject generateKeyPair() {
        JO ret = new JO(PropertyMap.newMap());
        SM2KeyPair keyPair = org.zz.gmhelper.SM2Util.generateSM2KeyPair();
        ret.put("publicKey", keyPair.getPublicKeyStr(), false);
        ret.put("privateKey", keyPair.getPrivateKeyStr(), false);
        return ret;
    }

    public static ScriptObject sign(String content, ScriptObjectMirror keyPair) {
        JO ret = new JO(PropertyMap.newMap());
        try {
            BigInteger privateKey = new BigInteger(keyPair.getMember("privateKey").toString(), 16);
            ECPrivateKeyParameters priKey =
                    new ECPrivateKeyParameters(privateKey, org.zz.gmhelper.SM2Util.DOMAIN_PARAMS);
            byte[] sign = org.zz.gmhelper.SM2Util.sign(priKey, content.getBytes());
            ret.put("status", "success", false);
            ret.put("signature", ByteUtils.toHexString(sign), false);
        } catch (Exception e) {
            ret.put("status", "failed", false);
            ret.put("message", "invalid keyPair", false);
        }
        return ret;
    }

    public static ScriptObject verify(String content, String signature, String pubKeyStr) {
        JO ret = new JO(PropertyMap.newMap());
        try {
            byte[] sig = ByteUtils.fromHexString(signature);
            ECPublicKeyParameters pubKey =
                    BCECUtil.createECPublicKeyFromStrParameters(
                            pubKeyStr,
                            org.zz.gmhelper.SM2Util.CURVE,
                            org.zz.gmhelper.SM2Util.DOMAIN_PARAMS);
            boolean value = org.zz.gmhelper.SM2Util.verify(pubKey, content.getBytes(), sig);
            if (value) ret.put("status", "success", false);
            else ret.put("status", "failed", false);
            ret.put("result", value, false);
        } catch (Exception e) {
            ret.put("status", "failed", false);
            ret.put("result", "invalid keyPair or signature ", false);
            e.printStackTrace();
        }
        return ret;
    }

    public static String encrypt(String content, String pubkey) {
        try {
            return ByteUtils.toHexString(
                    org.zz.gmhelper.SM2Util.encrypt(
                            SM2KeyPair.publicKeyStr2ECPoint(pubkey), content.getBytes()));
        } catch (InvalidCipherTextException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String decrypt(String content, String privateKey) {
        try {
            ECPrivateKeyParameters privateKeyParam =
                    new ECPrivateKeyParameters(
                            new BigInteger(privateKey, 16), org.zz.gmhelper.SM2Util.DOMAIN_PARAMS);
            return new String(
                    org.zz.gmhelper.SM2Util.decrypt(
                            privateKeyParam, ByteUtils.fromHexString(content)));
        } catch (InvalidCipherTextException e) {
            e.printStackTrace();
        }
        return null;
    }
}
