package com.emoon.openplatform.controller;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
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.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.emoon.common.core.domain.R;
import com.emoon.common.core.utils.StringUtils;
import com.emoon.openplatform.domain.AskInfoDo;
import com.emoon.openplatform.domain.ModelDo;
import com.emoon.openplatform.domain.SysProjectDo;
import com.emoon.openplatform.domain.bo.ModelBo;
import com.emoon.openplatform.domain.dto.resp.CheckResp;
import com.emoon.openplatform.enums.SystemEnum;
import com.emoon.openplatform.service.IAskInfoService;
import com.emoon.openplatform.service.IModelService;
import com.emoon.openplatform.service.ISysProjectService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;

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

    private final ISysProjectService sysProjectService;

    private final IAskInfoService askInfoService;

    private final IModelService modelService;

    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";

    /**
     * 获取获取短令牌接口
     *
     * @param information 业务系统通过前 10 步处理后的加密字符串
     *                    e.g.
     *                    eyJlbmNyeXB0ZWRCYXNlNjQiOiJQMzkwRExhQkN0c2xoSEpvXC9rU3pCS1NnWXY3aWFCQUFQMHFZS2F2ZHdIS3JCem4zRU
     *                    tDaWw3YjNyWTI5eXBINmFrZ2MxaVdqaktsc0FjeXFcLzlIUGI2cnNFYk9yZ0xVMDNJVytmUDU4MVU1KzJ0XC9GXC96YXJM
     *                    dVBMZk11REZvNmlYc3NVbkQ3ckpOOEZpaUFcLzBMb0FFbEJveWE0alRjWEk3YjF3XC9GV1orTXdXWVwvK3BZUG0yTWw3Wl
     *                    Q2XC9SRGdleU55UndFZTNXOTBxb0tpdTJNcmo4K0tiOFArY2RXd0lNaVpIb0xEZHVEc2tqXC85aWsrRFRZSXZTcnB3K0N5
     *                    d1ZxR0VCU1dKV0F1M2crdnQ4QUNER1wvSUM3RWJnNHZEc3JNWVUyZkV2UG9Xd2grMjlPNzU5Z1VRMDFPU2l4eE5Kb1Q1OE
     *                    Q1VVJCSkFlNFRzaTJTN0k1SGc5cG0yK3c0Y0M4MXZpMnZyOEk4Qng1UVhSa2RDaXl5Z2orajY5a1h1QXVmZm5hZWd0VHh2
     *                    ZjNURkVKeSszS1g3XC9NNGphVDhLVExZbGpickhCeGdzUHk4UVJjNmJTK0lNOXJ1b2NhblFoeHpTU0Z3K0NQRERVNlJ3RE
     *                    lYajM0RGRnPT0iLCJzbUlWIjoiMTIzNDU2Nzg5MTQ3ODUyMyIsInB1YmxpY0tleSI6InRISlpwOW1KUVBKNENKQXUxOUY2
     *                    dmhJVmExY3laaFA4In0=
     * @return
     */
    @PostMapping("/getToken")
    public R<String> getToken(@RequestParam("information") String information) {
        if (StringUtils.isBlank(information)) {
            return R.fail(SystemEnum.ILLEGAL_REQUEST.getCode(), SystemEnum.ILLEGAL_REQUEST.getMessage());
        }
        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 = sysProjectService.queryByPublicKey(publicKey);
        if (ObjectUtil.isNull(sysProjectDo) || StringUtils.isBlank(sysProjectDo.getPrivateKey())) {
            return R.fail(SystemEnum.DECRYPTION_ERROR.getCode(), SystemEnum.DECRYPTION_ERROR.getMessage());
        }
        // 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(SystemEnum.DECRYPTION_ERROR.getCode(), SystemEnum.DECRYPTION_ERROR.getMessage());
        }
        // 请求信息整理
        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();
        Integer insertCnt = askInfoService.insertAskInfo(askInfoDo);
        log.info("insert askInfo: {}", insertCnt);
        // 将 token 返回给前端
        return R.ok(SystemEnum.SUCCESS.getMessage(), 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);
    }


    @PostMapping("/check")
    public R<CheckResp> check(@RequestParam String token) {
        // 1. 通过获取的 token 获取对应的 encryption
        AskInfoDo askInfoDo = askInfoService.findByToken(token);
        if (askInfoDo == null) {
            return R.fail(SystemEnum.ILLEGAL_REQUEST.getCode(), SystemEnum.ILLEGAL_REQUEST.getMessage());
        }
        // 2. 解码并解析encryption
        String decodeInformation = base64UrlDecode(askInfoDo.getEncryption());
        // 解析 json
        JSONObject informationObject = JSONUtil.parseObj(decodeInformation);
        // 3. 获取解密所需参数
        String smIV = informationObject.getStr(INFO_KEY_SM_IV);
        String publicKey = informationObject.getStr(INFO_KEY_PUBLIC_KEY);
        String encryptedBase64 = informationObject.getStr(INFO_KEY_ENCRYPTED_BASE_64);
        // 4. 获取私钥
        SysProjectDo sysProjectDo = sysProjectService.queryByPublicKey(publicKey);
        if (sysProjectDo == null) {
            return R.fail(SystemEnum.INVALID_PUBLIC_KEY.getCode(), SystemEnum.INVALID_PUBLIC_KEY.getMessage());
        }
        // 5. sm4 解密配置
        JSONObject decryptedData;
        try {
            byte[] keyBytes = sysProjectDo.getPrivateKey().getBytes(StandardCharsets.UTF_8);
            byte[] smIVBytes = smIV.getBytes(StandardCharsets.UTF_8);
            // 初始化 SM4 加密器
            SM4 sm4 = new SM4(Mode.CBC,
                Padding.PKCS5Padding,
                keyBytes,
                smIVBytes);
            // 解密流程
            byte[] encryptedBytes = Base64.decode(encryptedBase64);
            byte[] decryptedBytes = sm4.decrypt(encryptedBytes);
            String decryptedStr = new String(decryptedBytes, StandardCharsets.UTF_8);
            String finalDecrypt = new String(Base64.decode(decryptedStr), StandardCharsets.UTF_8);
            decryptedData = JSONUtil.parseObj(finalDecrypt);
        } catch (Exception e) {
            return R.fail(SystemEnum.DECRYPTION_ERROR.getCode(), SystemEnum.DECRYPTION_ERROR.getMessage());
        }
        // 6. 验证输入参数格式
        if (!decryptedData.containsKey("input") || !(decryptedData.get("input") instanceof List)) {
            return R.fail(SystemEnum.INPUT_MUST_BE_ARRAY.getCode(), SystemEnum.INPUT_MUST_BE_ARRAY.getMessage());
        }
        // 7. 获取模型和网络信息
        String model = decryptedData.getStr("model");
        Integer network = decryptedData.getInt("network");
        // 8. 验证模型是否存在
        List<ModelDo> models = modelService.search(ModelBo.builder()
            .model(model)
            .build());
        if (CollUtil.isEmpty(models)) {
            return R.fail(SystemEnum.MODEL_NOT_EXISTS.getCode(), SystemEnum.MODEL_NOT_EXISTS.getMessage());
        }
        // 9. 验证网络状态是否支持
        for (ModelDo modelDo : models) {
            if (!network.equals(modelDo.getNetwork())) {
                return R.fail(SystemEnum.MODEL_NOT_SUPPORT_NETWORK.getCode(), SystemEnum.MODEL_NOT_SUPPORT_NETWORK.getMessage());
            }
        }
        // 10. 验证模型权限
        Long modelId = models.get(0).getId();
        if (!CollUtil.contains(sysProjectDo.getModelIds(), modelId.toString())) {
            return R.fail(SystemEnum.PUBLIC_KEY_NO_MODEL_PERMISSION.getCode(), SystemEnum.PUBLIC_KEY_NO_MODEL_PERMISSION.getMessage());
        }
        return R.ok(CheckResp.builder()
//            .input(decryptedData.getStr("input"))
            .modelId(modelId)
            .build());
    }
}

