package com.qmth.boot.tools.codec;

import com.qmth.boot.tools.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;

public class CodecUtils {

    private static final String SHA1_ALGORITHM = "SHA-1";

    private static final String SHA256_ALGORITHM = "SHA-256";

    private static final String MD5_ALGORITHM = "MD5";

    public static String toBase64(byte[] value) {
        return value != null ? Base64.getEncoder().encodeToString(value) : StringUtils.EMPTY;
    }

    public static byte[] fromBase64(String value) {
        return value != null ? Base64.getDecoder().decode(value) : null;
    }

    public static String toHexString(byte[] value) {
        return value != null ? DatatypeConverter.printHexBinary(value) : StringUtils.EMPTY;
    }

    public static byte[] fromHexString(String value) {
        return value != null ? DatatypeConverter.parseHexBinary(value) : null;
    }

    public static byte[] sha1(String value) {
        return value != null ? digest(value.getBytes(StandardCharsets.UTF_8), SHA1_ALGORITHM) : null;
    }

    public static byte[] sha256(String value) {
        return value != null ? digest(value.getBytes(StandardCharsets.UTF_8), SHA256_ALGORITHM) : null;
    }

    public static byte[] md5(String value) {
        return value != null ? digest(value.getBytes(StandardCharsets.UTF_8), MD5_ALGORITHM) : null;
    }

    public static byte[] md5(byte[] value) {
        return value != null ? digest(value, MD5_ALGORITHM) : null;
    }

    public static byte[] md5(File file) {
        BufferedInputStream ins = null;
        try {
            ins = new BufferedInputStream(new FileInputStream(file));
            final MessageDigest digest = getMd5();
            IOUtils.copy(ins, null, (buffer, length) -> digest.update(buffer, 0, length));
            return digest.digest();
        } catch (Exception e) {
            return null;
        } finally {
            IOUtils.closeQuietly(ins);
        }
    }

    public static byte[] digest(byte[] input, String algorithm) {
        try {
            return MessageDigest.getInstance(algorithm).digest(input);
        } catch (Exception e) {
            return null;
        }
    }

    public static MessageDigest getMd5() {
        try {
            return MessageDigest.getInstance(MD5_ALGORITHM);
        } catch (Exception e) {
            return null;
        }
    }

    public static byte[] hmacsha256(byte[] key, byte[] data) {
        try {
            // 初始化HMAC密钥规格，指定算法为HMAC-SHA256并使用提供的密钥。
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256");
            // 获取Mac实例，并通过getInstance方法指定使用HMAC-SHA256算法。
            Mac mac = Mac.getInstance("HmacSHA256");
            // 使用密钥初始化Mac对象。
            mac.init(secretKeySpec);
            // 执行HMAC计算，通过doFinal方法接收需要计算的数据并返回计算结果的数组。
            return mac.doFinal(data);
        } catch (Exception e) {
            return null;
        }
    }

    public static String urlEncode(String text) {
        try {
            return URLEncoder.encode(text, StandardCharsets.UTF_8.name());
        } catch (Exception e) {
            return text;
        }
    }

    public static String urlDecode(String text) {
        try {
            return URLDecoder.decode(text, StandardCharsets.UTF_8.name());
        } catch (Exception e) {
            return text;
        }
    }

}
