package com.codvision.commoncore.utils;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.CryptoException;
import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.SignAlgorithm;

import java.security.*;

/**
 * @author hxl
 */
public class LySign {

    /**
     * 算法
     */
    protected String algorithm;

    protected String algorithmAfterWith;
    /**
     * 公钥
     */
    protected PublicKey publicKey;
    /**
     * 私钥
     */
    protected PrivateKey privateKey;

    /**
     * 签名，用于签名和验证
     */
    protected Signature signature;

    public LySign(SignAlgorithm algorithmE, byte[] privateKey, byte[] publicKey) {
        this.algorithm = algorithmE.getValue();
        this.algorithmAfterWith = KeyUtil.getAlgorithmAfterWith(this.algorithm);
        this.privateKey = SecureUtil.generatePrivateKey(this.algorithmAfterWith, privateKey);
        this.publicKey = SecureUtil.generatePublicKey(this.algorithmAfterWith, publicKey);
        try {
            this.signature = Signature.getInstance(algorithm);
        } catch (NoSuchAlgorithmException e) {
            throw new CryptoException(e);
        }
    }

    public static LySign of(SignAlgorithm algorithm, String privateKey, String publicKey, boolean hexStr) {
        byte[] privateBytes;
        byte[] publicBytes;
        if (hexStr) {
            privateBytes = HexUtil.decodeHex(privateKey);
            publicBytes = HexUtil.decodeHex(publicKey);
        } else {
            privateBytes = Base64.decode(privateKey);
            publicBytes = Base64.decode(publicKey);
        }
        return new LySign(algorithm, privateBytes, publicBytes);
    }

    public String sign(String data) {
        try {
            signature.initSign(privateKey);
            signature.update(data.getBytes());
            byte[] sign = signature.sign();
            return HexUtil.encodeHexStr(sign, false);
        } catch (InvalidKeyException | SignatureException e) {
            throw new CryptoException(e);
        }
    }

    public boolean verify(String data, String sign) {
        try {
            signature.initVerify(publicKey);
            signature.update(data.getBytes());
            return signature.verify(HexUtil.decodeHex(sign));
        } catch (InvalidKeyException | SignatureException e) {
            throw new CryptoException(e);
        }
    }
}
