package com.emoon.openplatform.controller;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.crypto.symmetric.SM4;
import cn.hutool.http.HttpStatus;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.emoon.openplatform.domain.AskInfoDo;
import com.emoon.openplatform.domain.SysProjectDo;
import com.emoon.openplatform.mapper.AskInfoMapper;
import com.emoon.openplatform.service.IAskInfoService;
import com.emoon.openplatform.service.ISysProjectService;
import com.emoon.openplatform.util.HttpUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @author destiny
 * @description:
 * @date 2025/9/23 17:44
 */
@Slf4j
@RestController
@RequestMapping("/Send")
@CrossOrigin(origins = "*")
@RequiredArgsConstructor
public class TokenController {

    private final ISysProjectService ISysProjectService;

    private final AskInfoMapper askInfoMapper;

    public static final String NETWORK = "1";
    public static final String NETWORK_LOCAL = "2";
    public static final String INFO_KEY_SM_IV = "smIV";
    public static final String INFO_KEY_PUBLIC_KEY = "publicKey";
    public static final String INFO_KEY_ENCRYPTED_BASE_64 = "encryptedBase64";
    @Value("${sm4.key}")
    private String sm4Key;

    @Value("${sm4.private-key}")
    private String sm4PrivateKey;

    @Value("${sm4.public-key}")
    private String sm4PublicKey;

    @Value("${sm4.open-url}")
    private String sm4OpenUrl;

    @Value("${sm4.open-url-local}")
    private String sm4OpenUrlLocal;

    @PostMapping("/dataSM4")
    public R<String> getToken(@RequestParam(required = false, defaultValue = "") String token,
                              @RequestParam String model,
                              @RequestParam String network,
                              @RequestParam("data") String dataJson) {
        try {
            String result = dataSM4(token, model, network, dataJson);
            return R.ok(result);
        } catch (Exception e) {
            log.error("Failed to get token: {}", e.getMessage(), e);
            return R.fail(HttpStatus.HTTP_INTERNAL_ERROR, "获取令牌失败: " + e.getMessage());
        }
    }

    public String dataSM4(String token, String model, String network, String dataJson) throws Exception {
        // 判断该请求是否需要生成token
        if ("noUse".equals(token)) {
            return "noToken";
        }

        // 组装请求的数据为base64格式
        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, Object> data = new HashMap<>();
        data.put("model", model);
        data.put("network", network);

        // 解析输入数据
        Object inputData = objectMapper.readValue(dataJson, Object.class);
        data.put("input", inputData);

        String jsonData = objectMapper.writeValueAsString(data);
        System.out.println("参数标记: " + jsonData);

        // Base64编码
        String base64Data = Base64.encodeStr(jsonData.getBytes(StandardCharsets.UTF_8), true, true);

        // 对请求的参数进行SM4加密

        byte[] encryptedBinary = sm4Encrypt(base64Data, sm4PrivateKey, sm4Key);
        String encryptedBase64 = Base64.encodeStr(encryptedBinary, true, true);

        // 创建最终的含有SM4的IV的数据
        Map<String, String> modifiedDataMap = new HashMap<>();
        modifiedDataMap.put("encryptedBase64", encryptedBase64);
        modifiedDataMap.put("smIV", sm4Key);
        modifiedDataMap.put("publicKey", sm4PublicKey);

        String modifiedDataJson = objectMapper.writeValueAsString(modifiedDataMap);
        String modifiedDataBase64 = Base64.encodeStr(modifiedDataJson.getBytes(StandardCharsets.UTF_8), true, true);

        // 将 '+' 替换为 '-'，'/' 替换为 '_'
        String modifiedData = modifiedDataBase64.replace('+', '-').replace('/', '_');

        // 将加密的参数发送给开放平台，获取短令牌
        String url;
        if (StringUtils.equals(NETWORK, network)) {
            url = sm4OpenUrl + "/Apis/getToken";
        } else if (StringUtils.equals(NETWORK_LOCAL, network)) {
            url = sm4OpenUrlLocal + "/Apis/getToken";
        } else {
            throw new IllegalArgumentException("Invalid network parameter");
        }


        Map<String, String> encryption = new HashMap<>();
        encryption.put("information", modifiedData);

        String response = HttpUtil.curlPost(url, encryption);
        // 解析响应获取token（这里简化处理，实际应使用JSON解析库）
        // 假设响应格式为 {"token":"xxx","code":0}

        return parseTokenFromResponse(response);
    }

    // 简化的响应解析方法
    private String parseTokenFromResponse(String response) {
        // 实际应该使用JSON解析库如Jackson或Gson
        // 这里简化处理，假设响应格式为 {"token":"xxx","code":0}
        int start = response.indexOf("\"token\":\"") + 9;
        int end = response.indexOf("\"", start);
        return response.substring(start, end);
    }

    // SM4加密方法（使用AES算法模拟SM4）
    private byte[] sm4Encrypt(String data, String key, String iv) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
        return cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 获取令牌
     *
     * @param information
     * @return
     */
    @PostMapping("/getToken")
    public R<String> getToken(@RequestParam("information") String information) {
        if (StringUtils.isBlank(information)) {
            return R.fail(6, "非法请求，已拒绝。");
        }
        String subInformation = information.length() > 20 ? information.substring(0, 20) : information;
        long timestamp = System.currentTimeMillis() / 1000;
        MD5 md5 = new MD5();
        String data = subInformation + timestamp + RandomUtil.randomNumbers(5) + 10000;
        String token = new String(HexUtil.encodeHex(md5.digest(data, CharsetUtil.UTF_8)));
        // URL安全的 Base64 decode
        String decodeInfo = base64UrlDecode(information);
        log.info("decodeInfo: {}", decodeInfo);
        JSONObject infoObject = JSONUtil.parseObj(decodeInfo);
        // SM4解密
        String smIV = (String) infoObject.get(INFO_KEY_SM_IV);
        String publicKey = (String) infoObject.get(INFO_KEY_PUBLIC_KEY);
        String encryptedBase64 = (String) infoObject.get(INFO_KEY_ENCRYPTED_BASE_64);
        SysProjectDo sysProjectDo = ISysProjectService.queryByPublicKey(publicKey);
        if (ObjectUtil.isNull(sysProjectDo) || StringUtils.isBlank(sysProjectDo.getPrivateKey())) {
            return R.fail(0, "解密错误，请核对仔细核对参数");
        }
        // SM4 解密配置
        SM4 sm4 = new SM4(Mode.CBC,
            Padding.PKCS5Padding,
            sysProjectDo.getPrivateKey().getBytes(StandardCharsets.UTF_8),
            smIV.getBytes(StandardCharsets.UTF_8));
        // 解密过程
        byte[] encryptedBytes = Base64.decode(encryptedBase64);
        String decrypted = sm4.decryptStr(encryptedBytes);
        String decodedDecrypted = new String(Base64.decode(decrypted));
        JSONObject decryptedInfo = JSONUtil.parseObj(decodedDecrypted);
        if (decryptedInfo.isEmpty()) {
            return R.fail(0, "解密错误，请核对仔细核对参数");
        }
        // 请求信息整理
        HashMap<String, Object> dataMap = MapUtil.newHashMap();
        dataMap.put("smIV", smIV);
        dataMap.put("publicKey", publicKey);
        dataMap.put("model", decryptedInfo.getStr("model"));
        dataMap.put("network", decryptedInfo.getStr("network"));
        dataMap.put("input", decryptedInfo.get("input"));
        // 构建数据库记录
        AskInfoDo askInfoDo = AskInfoDo.builder()
            .token(token)
            .decrypt(JSONUtil.toJsonStr(dataMap))
            .encryption(information)
            .time(timestamp)
            .build();
        int insertCnt = askInfoMapper.insert(askInfoDo);
        log.info("insert askInfo: {}", insertCnt);
        // 将 token 返回给前端
        return R.ok(token);
    }

    private String base64UrlDecode(String information) {
        String result = information.replace('-', '+').replace('_', '/');
        int padding = result.length() % 4;
        if (padding != 0) {
            result += "====".substring(0, 4 - padding);
        }
        return Base64.decodeStr(result, StandardCharsets.UTF_8);
    }

}
