package com.sonic.common.utils;

import com.amazonaws.services.cloudfront.util.SignerUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.PrivateKey;
import java.util.Base64;
import java.util.Date;

/**
 * @Author code
 * @Description CDN节点URL签名访问
 */
@Component
public class CloudFrontSignerUtils {

    /**
     * 模糊图片的尺寸
     */
    public static final String BLURRY_IMG_468_600 = "?x-oss-process=image/resize,w_468,h_600&Tag=1&v=1";
    public static final String BLURRY_IMG_800_800 = "?x-oss-process=image/resize,w_800,h_800&Tag=1&v=1";
    public static final String BLURRY_ORG_IMG = "?Tag=1&v=1";

    /**
     * 清晰图片的尺寸
     */
    public static final String IMG_468_600 = "?x-oss-process=image/resize,w_468,h_600&v=1";
    public static final String IMG_800_800 = "?x-oss-process=image/resize,w_800,h_800&v=1";
    public static final String ORG_IMG = "?v=1";

    /**
     * 永不过期
     */
    public static final Long EXP_TIME_2037 = 2114227200000L;

    @Value("${cloudFront.keyPairId.url:}")
    private String cloudFrontKeyPairId;

    @Value("${cloudFront.privateKey.url:}")
    private String cloudFrontPrivateKeyUrl;

    private static PrivateKey privateKey;

    /**
     * 获取私钥对象
     * @return
     */
    private PrivateKey getPrivateKey() {
        return getPrivateKey(cloudFrontPrivateKeyUrl);
    }

    /**
     * 获取私钥对象
     * @return
     */
    private PrivateKey getPrivateKey(String privateKeyPemUrl) {
        if(privateKey != null) {
            return privateKey;
        }
        try {
            File file = downloadRemoteFile(privateKeyPemUrl);
            privateKey = SignerUtils.loadPrivateKey(file);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return privateKey;
    }

    /**
     * 远程下载私钥pem文件
     * @param remoteUrl
     * @return
     * @throws IOException
     */
    public File downloadRemoteFile(String remoteUrl) throws IOException {
        // 创建 URL 对象
        URL url = new URL(remoteUrl);
        // 打开 URL 的输入流
        try (InputStream inputStream = url.openStream()) {
            // 将输入流数据写入到 File 对象
            File localFile = new File("private_key.pem");
            try (OutputStream outputStream = new FileOutputStream(localFile)) {
                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
            }
            return localFile;
        }
    }

    /**
     * 图片访问URL签名处理
     * @param fileUrl   文件全路径
     * @param expDate   过期时间
     * @return
     * @throws InvalidKeyException
     */
    private String cannedPolicySigner(String fileUrl, Date expDate) throws InvalidKeyException {
        //生成策略
        String policy = SignerUtils.buildCannedPolicy(fileUrl, expDate);
        //将策略进行base64签名
        String policyBase64 = base64Encode(policy);
        //将策略进行参数签名
        String policySign = SignerUtils.makeBytesUrlSafe(SignerUtils.signWithSha1RSA(policy.getBytes(), getPrivateKey()));

        StringBuffer URL = new StringBuffer();
        URL.append(fileUrl);
        URL.append("&Policy=").append(policyBase64.replace('+', '-').replace('=', '_').replace('/', '~'));
        URL.append("&Signature=").append(policySign.replace('+', '-').replace('=', '_').replace('/', '~'));
        URL.append("&Key-Pair-Id=").append(cloudFrontKeyPairId);
        //获取完整签名后的URL访问路径
        return URL.toString();
    }


    /**
     * 图片访问URL签名处理
     * @param fileUrl   文件全路径
     * @param expDate   过期时间
     * @param ip        允许访问的IP地址
     * @return
     * @throws InvalidKeyException
     */
    private String customPolicySigner(String fileUrl, Date expDate, String ip) throws InvalidKeyException {
        //生成策略
        String policy = SignerUtils.buildCustomPolicy(fileUrl, expDate, new Date(), ip + "\\/32");
        //将策略进行base64签名
        String policyBase64 = base64Encode(policy);
        //将策略进行参数签名
        String policySign = SignerUtils.makeBytesUrlSafe(SignerUtils.signWithSha1RSA(policy.getBytes(), getPrivateKey()));

        StringBuffer URL = new StringBuffer();
        URL.append(fileUrl);
        URL.append("&Policy=").append(policyBase64.replace('+', '-').replace('=', '_').replace('/', '~'));
        URL.append("&Signature=").append(policySign.replace('+', '-').replace('=', '_').replace('/', '~'));
        URL.append("&Key-Pair-Id=").append(cloudFrontKeyPairId);
        //获取完整签名后的URL访问路径
        return URL.toString();
    }

    /**
     * 参数签名方法
     * @param fileUrl
     * @param expDate
     * @param ip
     * @return
     */
    public String signer(String fileUrl, Date expDate, String ip) throws InvalidKeyException {
//        //判断ip地址是否是ipV4的地址
//        if(StringUtils.isNotEmpty(ip) && IpAddressUtils.checkIpV4(ip)) {
//            //使用自定义策略进行签名
//            return customPolicySigner(fileUrl, expDate, ip);
//        }
        //使用默认策略进行签名
        return cannedPolicySigner(fileUrl, expDate);
    }

    /**
     * 对入参数据进行 base64处理
     * @param input
     * @return
     */
    public String base64Encode(String input) {
        byte[] encodedBytes = Base64.getEncoder().encode(input.getBytes(StandardCharsets.UTF_8));
        return new String(encodedBytes, StandardCharsets.UTF_8);
    }

    /**
     * 将数据根据规则替换后将数据解析成json字符串
     * @param input
     * @return
     */
    public String base64Decode(String input) {
        // 替换规则
        input = input.replace('-', '+').replace('_', '=').replace('~', '/');
        // 解码 Base64 字符串为字节数组
        byte[] decodedBytes = Base64.getDecoder().decode(input);
        // 将字节数组转换为字符串
        String decodedJson = new String(decodedBytes, StandardCharsets.UTF_8);
        return decodedJson;
    }

}
