package com.awspaas.user.apps.donenow_sys.controller;

import com.actionsoft.bpms.commons.htmlframework.HtmlPageTemplate;
import com.actionsoft.bpms.commons.session.SessionImpl;
import com.actionsoft.bpms.commons.session.model.SessionModel;
import com.actionsoft.bpms.server.bind.annotation.Controller;
import com.actionsoft.bpms.server.bind.annotation.Mapping;
import com.actionsoft.exception.BPMNError;
import com.actionsoft.sdk.local.SDK;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.math3.util.Pair;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

@Controller
public class testController {
    @Mapping(value = "donenow_sys.jiuye_index", session = false, noSessionEvaluate = "无安全隐患", noSessionReason = "用于MVC框架稳定性测试")
    public String jiuye_index() {
        System.out.println("jiuye_index");
        Map<String, Object> map = new HashMap<>();
        map.put("uid", "jiuye_test1");
        //SessionModel session = new SessionImpl().registerSession("A", "jiuye_test1", "cn", "", "pc", false, new HashMap());
        String sid = "";
        try {
            String ses = SDK.getPortalAPI().createClientSessionByPC("jiuye_test1", "Aa1", "cn", "", "");
            System.out.println(ses);
            JSONObject obj = JSONObject.parseObject(ses);
            sid = obj.getJSONObject("data").getString("sid");
            map.put("sid", sid);

        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(sid);


        map.put("url", SDK.getPortalAPI().getPortalUrl() + "/r/w?sid=" + sid + "&cmd=CLIENT_P_PORTAL_HOME&id=com.awspaas.user.apps.portal.1751251354216&msaAppId=com.awspaas.user.apps.portal.175125135421");

        return HtmlPageTemplate.merge("jiuye_index.html", map);
    }


    @Mapping(value = "donenow_sys.jiuye_index2", session = false, noSessionEvaluate = "无安全隐患", noSessionReason = "用于MVC框架稳定性测试")
    public String jiuye_index2() throws Exception {
        System.out.println("jiuye_index");
        Map<String, Object> map = new HashMap<>();
        map.put("uid", "jiuye_test1");
        //SessionModel session = new SessionImpl().registerSession("A", "jiuye_test1", "cn", "", "pc", false, new HashMap());

        String sid = "ck_21232f297a57a5a743894a0e4a801fc3_ck";

        map.put("sid", sid);


        JSONObject obj = JSONObject.parseObject(SDK.getPortalAPI().createClientSessionByPC("jiuye_test1", "Aa1", "cn", null));
        JSONObject obj2 = JSONObject.parseObject(obj.getString("data"));
        String createSid = obj2.getString("sid");

        map.put("url", SDK.getPortalAPI().getPortalUrl() + "/r/w?sid=" + sid + "&cmd=CLIENT_P_PORTAL_HOME&id=com.awspaas.user.apps.portal.1751251354216&msaAppId=com.awspaas.user.apps.portal.175125135421");

        String url = SDK.getPortalAPI().getPortalUrl() + "/r/w?sid=" + sid + "&cmd=CLIENT_P_PORTAL_HOME&id=com.awspaas.user.apps.portal.1751251354216&msaAppId=com.awspaas.user.apps.portal.175125135421";

        String modifiedHtml = getModifiedContent(url);

        return modifiedHtml;
    }


    public static String getModifiedContent(String url) {
        try {
            // 加载HTML文档
            Document doc = Jsoup.connect(url)
                    .userAgent("Mozilla/5.0")
                    .timeout(10000)
                    .ignoreContentType(true) // 忽略内容类型检查
                    .followRedirects(true)  // 允许重定向
                    .execute()
                    .parse();

            // 移除顶部元素
            Element topElement = doc.select("#app > div > div.aws-portal.top-nav > section > section > header.el-header.public-header-border > div > div").first();
            if (topElement != null) {
                topElement.remove();
            }

            // 修改导航菜单
            Element navUl = doc.select("#app > div > div.aws-portal.top-nav > section > section > header.el-header.top-nav-border > div > div > div > div.menu-box > ul").first();
            if (navUl != null) {
                // 保留第一个li，删除其他所有li
                for (int i = navUl.childrenSize() - 1; i >= 1; i--) {
                    navUl.child(i).remove();
                }

                // 添加新菜单项
                addMenuItem(navUl, "学校", "school");
                addMenuItem(navUl, "单位", "company");
                addMenuItem(navUl, "学生", "student");
            }

            return doc.outerHtml();
        } catch (IOException e) {
            System.err.println("处理HTML时出错: " + e.getMessage());
            return null;
        }
    }

    private static void addMenuItem(Element parent, String text, String id) {
        Element li = parent.ownerDocument().createElement("li");
        li.attr("class", "el-sub-menu");
        li.attr("role", "menuitem");
        li.attr("id", "custom-" + id);

        Element a = parent.ownerDocument().createElement("a");
        a.attr("href", "javascript:void(0);");
        a.attr("class", "el-menu-item");
        a.text(text);

        li.appendChild(a);
        parent.appendChild(li);
    }


    @Mapping(value = "donenow_sys.test", session = false, noSessionEvaluate = "无安全隐患", noSessionReason = "用于MVC框架稳定性测试")
    public String test(String plainText, int keySize) throws Exception {
        return aesKeyGeneration(plainText, keySize);
    }

    @Mapping(value = "donenow_sys.test1", session = false, noSessionEvaluate = "无安全隐患", noSessionReason = "用于MVC框架稳定性测试")
    public String test1(String plainText, String aesKey) throws Exception {

        String result = "\r\n 加密原文:" + plainText;
        result += "\r\n 加密密钥:" + aesKey;
        try {
            String encryptedTextECB = encryptWithECB(plainText, aesKey);

            result += "\r\n ECB 加密密文encodeURIComponent:" + encryptedTextECB;
            result += "\r\n ECB 加密密文:" + encodeURIComponent(encryptedTextECB);

            String encryptedTextCBC = encryptWithCBC(plainText, aesKey);

            result += "\r\n CBC 加密后encodeURIComponent:" + encryptedTextCBC;
            result += "\r\n CBC 加密后:" + encodeURIComponent(encryptedTextCBC);
        } catch (Exception e) {

        }


        return result;
    }

    @Mapping(value = "donenow_sys.test2", session = false, noSessionEvaluate = "无安全隐患", noSessionReason = "用于MVC框架稳定性测试")
    public String test2(String encryptedText, String aesKey) throws Exception {
        String result = "\r\n 加密原文:" + encryptedText;
        result += "\r\n 加密密钥:" + aesKey;
        try {
            String tokenResultCBC = decryptAuto(encryptedText, aesKey);

            result += "\r\n AES  CBC 解密结果:" + tokenResultCBC;

            String tokenResultECB = decryptAuto(encryptedText, aesKey);

            result += "\r\n AES EBC 解密结果:" + tokenResultECB;
        } catch (Exception e) {
            result += "异常:" + e.getMessage();
        }


        return result;
    }

    @Mapping(value = "donenow_sys.test3", session = false, noSessionEvaluate = "无安全隐患", noSessionReason = "用于MVC框架稳定性测试")
    public String test3(String encryptedText, String aesKey) throws Exception {
        String result = "\r\n 加密原文:" + encryptedText;
        result += "\r\n 加密密钥:" + aesKey;
        try {
            String tokenResultCBC = AESDecrypt(encryptedText, aesKey);

            result += "\r\n AES  CBC 解密结果:" + tokenResultCBC;

            String tokenResultECB = AESDecrypt(encryptedText, aesKey);

            result += "\r\n AES EBC 解密结果:" + tokenResultECB;
        } catch (Exception e) {

        }


        return result;
    }

    /**
     * 生成 AES 密钥
     * @param plainText
     * @param keySize
     * @return
     * @throws Exception
     */
    public String aesKeyGeneration(String plainText, int keySize) throws Exception {
        // 生成 AES 密钥
        SecretKey secretKey = null;
        try {
            if (keySize == 128 || keySize == 192 || keySize == 256)
                secretKey = generateAESKey(keySize);
            else
                secretKey = generateAESKey(KEY_SIZE);//AES 支持的密钥长度：128、192、256 位
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        String base64Key = Base64.getEncoder().encodeToString(secretKey.getEncoded());
        String hexKey = bytesToHex(secretKey.getEncoded());

        String aesKey = "AES 密钥 (Base64): " + base64Key;
/*
        System.out.println("🔹 AES 密钥 (Base64):");
        System.out.println(base64Key);
        System.out.println("\r\n🔹 AES 密钥 (HEX):");

       /aesKey = aesKey + "\r\n AES 密钥 (HEX):" + hexKey;

        System.out.println(hexKey);

        // CBC 模式需要 IV
        byte[] iv = generateIV();
        String base64IV = Base64.getEncoder().encodeToString(iv);
        String hexIV = bytesToHex(iv);
        aesKey += "\r\n CBC 模式需要 IV";
        aesKey += "\r\n CBC 初始化向量 IV (Base64):" + base64IV;
        System.out.println("\r\n\r\n🔸 CBC 初始化向量 IV (Base64):");
        System.out.println(base64IV);
        aesKey += "\r\n CBC 初始化向量 IV (HEX):" + hexIV;
        System.out.println("\r\n🔸 CBC 初始化向量 IV (HEX):");
        System.out.println(hexIV);
*/

        aesKey += "\r\n 加密原文:" + plainText;

        String encryptedTextECB = encryptWithECB(plainText, base64Key);

        aesKey += "\r\n ECB 加密密文:" + encryptedTextECB;

        String encryptedTextCBC = encryptWithCBC(plainText, base64Key);

        aesKey += "\r\n CBC 加密后:" + encryptedTextCBC;

        String tokenResultECB = decryptAuto(encryptedTextECB, base64Key);

        aesKey += "\r\n AES EBC 解密结果:" + tokenResultECB;

        String tokenResultCBC = decryptAuto(encryptedTextCBC, base64Key);

        aesKey += "\r\n AES  CBC 解密结果:" + tokenResultCBC;


        return aesKey;
    }

    // AES 支持的密钥长度：128、192、256 位
    private static final int KEY_SIZE = 128; // 推荐使用256位
    // IV 长度固定为16字节（128位）
    private static final int IV_SIZE = 16;


    /**
     * 生成指定长度的 AES 密钥
     */
    public static SecretKey generateAESKey(int keySizeInBits) throws Exception {
        KeyGenerator kg = KeyGenerator.getInstance("AES");
        kg.init(keySizeInBits); // 可选值：128, 192, 256
        return kg.generateKey();
    }

    /**
     * 生成 16 字节的随机 IV（仅用于 CBC 等模式）
     */
    public static byte[] generateIV() {
        byte[] iv = new byte[IV_SIZE];
        new SecureRandom().nextBytes(iv);
        return iv;
    }


    /**
     * 将 byte[] 转换为十六进制字符串
     */
    public static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

    // AES加密方法
    public static String encrypt(String plainText, SecretKey secretKey, IvParameterSpec iv) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
        byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
        return Base64.getEncoder().encodeToString(encryptedBytes); // 返回Base64编码的字符串
    }

    // 使用AES/ECB/PKCS5Padding模式加密
    public static String encrypt(String plainText, SecretKey secretKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
        return Base64.getEncoder().encodeToString(encryptedBytes); // 返回Base64编码的字符串
    }


    /**
     * AES解密方法，默认使用CBC模式
     * @param encryptedToken
     * @param secretKey
     * @return
     * @throws Exception
     */
    public static String AESDecrypt(String encryptedToken, String secretKey) throws Exception {
        try {
            try {
                String result = AESDecrypt(encryptedToken, secretKey, "CBC");
                if (StringUtils.isBlank(result))
                    result = AESDecrypt(encryptedToken, secretKey, "ECB");
                return result;
            } catch (Exception e) {
                e.printStackTrace();
                return AESDecrypt(encryptedToken, secretKey, "ECB");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * AES解密方法，支持ECB和CBC模式
     * @param encryptedToken
     * @param secretKey
     * @param mode
     * @return
     * @throws Exception
     */
    public static String AESDecrypt(String encryptedToken, String secretKey, String mode) throws Exception {
        // 验证输入参数
        if (encryptedToken == null || encryptedToken.isEmpty()) {
            throw new IllegalArgumentException("加密字符串不能为空");
        }

        if (secretKey == null || secretKey.isEmpty()) {
            throw new IllegalArgumentException("密钥不能为空");
        }

        // 检查密钥长度
        int keyLength = secretKey.getBytes(StandardCharsets.UTF_8).length * 8;
        if (keyLength != 128 && keyLength != 192 && keyLength != 256) {
            throw new IllegalArgumentException("密钥长度必须是16、24或32字节 (分别对应128、192或256位)");
        }

        // 处理不同的加密模式
        String transformation;
        IvParameterSpec ivParameterSpec = null;

        switch (mode.toUpperCase()) {
            case "ECB":
                transformation = "AES/ECB/PKCS5Padding";
                break;
            case "CBC":
                transformation = "AES/CBC/PKCS5Padding";
                // 从加密字符串中提取IV (前16字节)
                byte[] encryptedBytes = Base64.getDecoder().decode(encryptedToken);
                if (encryptedBytes.length < 16) {
                    throw new IllegalArgumentException("CBC模式下加密数据长度必须至少为16字节");
                }

                byte[] ivBytes = new byte[16];
                System.arraycopy(encryptedBytes, 0, ivBytes, 0, 16);
                ivParameterSpec = new IvParameterSpec(ivBytes);

                // 实际加密数据从第16字节开始
                byte[] cipherTextBytes = new byte[encryptedBytes.length - 16];
                System.arraycopy(encryptedBytes, 16, cipherTextBytes, 0, cipherTextBytes.length);
                encryptedToken = Base64.getEncoder().encodeToString(cipherTextBytes);
                break;
            default:
                throw new IllegalArgumentException("不支持的加密模式: " + mode);
        }

        try {
            // 创建密钥规范
            SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "AES");

            // 初始化解密器
            Cipher cipher = Cipher.getInstance(transformation);
            if (ivParameterSpec != null) {
                cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
            } else {
                cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
            }

            // 执行解密
            byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedToken));
            return new String(decryptedBytes, StandardCharsets.UTF_8);

        } catch (Exception e) {
            // 记录详细的解密错误信息
            System.err.println("AES解密失败: " + e.getMessage());
            throw new Exception("解密过程中发生错误", e);
        }
    }


    private static final String AES_CBC = "AES/CBC/PKCS5Padding";
    private static final String AES_ECB = "AES/ECB/PKCS5Padding";

    // CBC 加密（IV 放在密文最前面）
    public static String encryptWithCBC(String plainText, String base64Key) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(base64Key);
        SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");

        byte[] iv = new byte[16];
        new SecureRandom().nextBytes(iv);

        Cipher cipher = Cipher.getInstance(AES_CBC);
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));

        byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
        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);
    }

    // ECB 加密
    public static String encryptWithECB(String plainText, String base64Key) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(base64Key);
        SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");

        Cipher cipher = Cipher.getInstance(AES_ECB);
        cipher.init(Cipher.ENCRYPT_MODE, key);

        byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encrypted);
    }

    // 自动识别 CBC / ECB 并解密
    public static String decryptAuto(String encryptedBase64, String base64Key) throws Exception {
        try {
            String result = decryptWithCBC(encryptedBase64, base64Key);
            if (StringUtils.isBlank(result))
                result = decryptWithECB(encryptedBase64, base64Key);
            return result;
        } catch (Exception e) {
            try {
                return decryptWithECB(encryptedBase64, base64Key);
            } catch (Exception ex) {
                throw new RuntimeException("无法解密，请确认密钥和加密模式是否正确");
            }
        }
    }

    // CBC 解密
    public static String decryptWithCBC(String encryptedBase64, String base64Key) throws Exception {
        byte[] combined = Base64.getDecoder().decode(encryptedBase64);
        if (combined.length < 16) throw new IllegalArgumentException("加密数据长度不足");

        byte[] iv = new byte[16];
        byte[] cipherText = new byte[combined.length - 16];

        System.arraycopy(combined, 0, iv, 0, 16);
        System.arraycopy(combined, 16, cipherText, 0, cipherText.length);

        byte[] keyBytes = Base64.getDecoder().decode(base64Key);
        SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");

        Cipher cipher = Cipher.getInstance(AES_CBC);
        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));

        byte[] decrypted = cipher.doFinal(cipherText);
        return new String(decrypted, StandardCharsets.UTF_8);
    }

    // ECB 解密
    public static String decryptWithECB(String encryptedBase64, String base64Key) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(base64Key);
        SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");

        Cipher cipher = Cipher.getInstance(AES_ECB);
        cipher.init(Cipher.DECRYPT_MODE, key);

        byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encryptedBase64));
        return new String(decrypted, StandardCharsets.UTF_8);
    }


    /**
     * URI 编码
     * @param s
     * @return
     */
    public static String encodeURIComponent(String s) {
        if (s == null) {
            return null;
        }
        try {
            String encoded = URLEncoder.encode(s, "UTF-8");

            // 替换 + -> %20
            encoded = encoded.replaceAll("\\+", "%20");

            // 替换 JavaScript 不会编码的字符
            encoded = encoded.replaceAll("\\%21", "!")      // !
                    .replaceAll("\\%27", "'")               // '
                    .replaceAll("\\%28", "(")               // (
                    .replaceAll("\\%29", ")")               // )
                    .replaceAll("\\%7E", "~")               // ~
                    .replaceAll("\\%2A", "\\*")             // *
                    .replaceAll("\\%2D", "-")               // -
                    .replaceAll("\\%5F", "_");              // _

            return encoded;

        } catch (UnsupportedEncodingException e) {
            // UTF-8 是标准支持的，所以理论上不会抛出异常
            return s;
        }
    }


    public Pair<String, Integer> getUserInfo() {
        String username = "zhangsan";
        int userId = 1001;


        SessionModel session = new SessionImpl().registerSession("A", "", "cn", "", "pc", false, new HashMap());
        if ((session == null) || (org.apache.commons.lang.StringUtils.isBlank(session.getSessionId()))) {
            throw new BPMNError("创建session失败，请检查用户名");
        }


        //SSOUtil ssoUtil = new SSOUtil();
        //String session = ssoUtil.registerClientSessionNoPassword("admin", "cn", SDK.getPortalAPI().getPortalUrl(), "pc");



        // 创建不可变的Pair对象（推荐，线程安全）

        return Pair.create(username, userId);
    }


}
