package org.jeecg.modules.adweb.payment.controller;

import com.google.common.collect.ImmutableMap;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.FastJsonUtil;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.*;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * Alibaba.com Pay
 *
 * <p>参考
 * https://alidocs.dingtalk.com/i/nodes/Amq4vjg890j11711tjabv6j0J3kdP0wQ?utm_scene=person_space
 *
 * @author wfansh
 */
@RestController
@RequestMapping("/payment/acp")
@Slf4j
public class ACPController {

    @Value("${payment.apc.encrypt-key}")
    private String encryptKey;

    @Value("${payment.apc.sign-key}")
    private String signKey;

    @Autowired ISysUserService sysUserService;

    /** 获取ACP URL里的参数 - 签名，加密 */
    @GetMapping(value = "/getUrlParams")
    @ResponseBody
    public Result<List<String>> getUrlParams() throws Exception {
        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        SysUser sysUser = sysUserService.getById(loginUser.getId());

        if (Objects.isNull(sysUser) || StringUtils.isBlank(sysUser.getSocialCreditCode())) {
            return Result.error("当前用户未配置社会信用代码");
        }

        // 待签名及加密的数据
        Map<String, String> params =
                ImmutableMap.of(
                        "mid",
                        sysUser.getId(),
                        "loginId",
                        sysUser.getUsername(),
                        "from",
                        "suhaotong",
                        "companyName",
                        sysUser.getCompanyName(),
                        "companyCode",
                        sysUser.getSocialCreditCode(),
                        "timestamp",
                        Long.toString(System.currentTimeMillis()));

        // 1. 签名
        String content = this.getSignatureContent(params);
        String signedParams = this.sign(content, signKey);

        // 2. 加密
        String encryptedParams = this.encrypt(FastJsonUtil.toJSONString(params), encryptKey);
        encryptedParams = URLEncoder.encode(encryptedParams, StandardCharsets.UTF_8);

        return Result.OK(List.of(signedParams, encryptedParams));
    }

    /**
     * 1.1 根据参数生成用于加签的字符串
     *
     * @param params 参数
     * @return 用于加签的字符串
     */
    private String getSignatureContent(Map<String, String> params) {
        if (params == null) {
            return null;
        } else {
            StringBuilder content = new StringBuilder();
            List<String> keys = new ArrayList<>(params.keySet());
            Collections.sort(keys);
            for (int i = 0; i < keys.size(); ++i) {
                String key = keys.get(i);
                String value = MapUtils.getString(params, key);
                content.append(i == 0 ? "" : "&").append(key).append("=").append(value);
            }
            return content.toString();
        }
    }

    /**
     * 1.2 生成字符串的SHA-256哈希签名
     *
     * @param content 原始字符串
     * @param signKey 签名秘钥
     * @return 十六进制格式的SHA-256哈希值
     */
    private String sign(String content, String signKey) throws NoSuchAlgorithmException {
        // 创建MessageDigest实例
        MessageDigest digest = MessageDigest.getInstance("SHA-256");

        // 计算哈希值
        byte[] hashBytes = digest.digest((content + signKey).getBytes(StandardCharsets.UTF_8));

        String base64Hash = Base64.getEncoder().encodeToString(hashBytes);

        return base64Hash;
    }

    /** 2. 加密方法 */
    private String encrypt(String plainText, String encryptKey) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(encryptKey);

        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");

        // 生成随机IV
        byte[] iv = new byte[16]; // 16 bytes for AES block
        new SecureRandom().nextBytes(iv);
        IvParameterSpec ivSpec = new IvParameterSpec(iv);

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec);

        byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));

        // 将IV和加密数据拼接后编码为Base64
        byte[] combined = new byte[iv.length + encrypted.length];
        System.arraycopy(iv, 0, combined, 0, iv.length);
        System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length);

        return Base64.getEncoder().encodeToString(combined);
    }
}
