package com.zcloud.basic.info.aspect;

import com.alibaba.cola.dto.SingleResponse;
import com.alibaba.cola.exception.BizException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.zcloud.basic.info.persistence.dataobject.CorpInfoKeyDO;
import com.zcloud.basic.info.service.CorpInfoKeyService;
import com.zcloud.basic.info.utils.SyncPageResponse;
import com.zcloud.gbscommon.utils.Sm2Util;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Aspect
@Component
@Slf4j
public class SyncResponseEncryptAspect {

    @Autowired
    private CorpInfoKeyService corpInfoKeyService;

    private static final long TIMESTAMP_TOLERANCE = 5 * 60 * 1000L;

    @Pointcut("execution(* com.zcloud.basic.info.web.sync.SyncController.*(..))")
    public void syncControllerPointcut() {}

    @Around("syncControllerPointcut()")
    public Object encrypt(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = getHttpServletRequest();

        String corpinfoId = request.getHeader("X-CORPINFO-ID");
        String timestamp = request.getHeader("X-TIMESTAMP");
        String signature = request.getHeader("X-SIGNATURE");

        if (corpinfoId == null || timestamp == null || signature == null) {
            throw new BizException("缺少必要的认证头信息");
        }

        long requestTime = Long.parseLong(timestamp);
        if (Math.abs(System.currentTimeMillis() - requestTime) > TIMESTAMP_TOLERANCE) {
            throw new BizException("请求已过期");
        }

        CorpInfoKeyDO keyDO = corpInfoKeyService.getByCorpinfoId(Long.parseLong(corpinfoId));
        if (keyDO == null) {
            throw new BizException("未找到对应的密钥配置");
        }
        if (keyDO.getPublicKey() == null || keyDO.getSignKey() == null) {
            throw new BizException("密钥配置不完整");
        }

        String body = getRequestBody(joinPoint);

        if (!sm2Verify(signature, corpinfoId, timestamp, body, keyDO)) {
            throw new BizException("签名验证失败");
        }

        Object result = joinPoint.proceed();
        if (result == null) {
            return result;
        }

        String className = result.getClass().getName();
        if (className.contains("SingleResponse")) {
            SingleResponse response = (SingleResponse) result;
            Object data = response.getData();
            if (data != null) {
                response.setData(encryptData(data, keyDO.getPublicKey()));
            }
        } else if (className.contains("SyncPageResponse") || className.contains("PageResponse") || className.contains("MultiResponse")) {
            SyncPageResponse response = (SyncPageResponse) result;
            Object data = response.getData();
            if (data != null) {
                response.setData(encryptData(data, keyDO.getPublicKey()));
            }
        }

        return result;
    }

    private HttpServletRequest getHttpServletRequest() {
        return ((org.springframework.web.context.request.ServletRequestAttributes)
                org.springframework.web.context.request.RequestContextHolder.getRequestAttributes())
                .getRequest();
    }

    private String getRequestBody(ProceedingJoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        if (args != null && args.length > 0) {
            for (Object arg : args) {
                if (arg != null && !(arg instanceof HttpServletRequest)) {
                    return JSON.toJSONString(arg);
                }
            }
        }
        return "";
    }

private boolean sm2Verify(String signature, String corpinfoId, String timestamp, String body, CorpInfoKeyDO keyDO) {
        try {
            String decrypted = Sm2Util.decryptBase64(signature, keyDO.getSignPrivateKey());
            JSONObject json = JSON.parseObject(decrypted);

            String jsonCorpinfoId = json.getString("corpinfoId");
            String jsonTimestamp = json.getString("timestamp");
            String jsonBody = json.getString("body");

            if (!corpinfoId.equals(jsonCorpinfoId)) {
                log.warn("corpinfoId不匹配: expected={}, actual={}", corpinfoId, jsonCorpinfoId);
                return false;
            }
            if (!timestamp.equals(jsonTimestamp)) {
                log.warn("timestamp不匹配: expected={}, actual={}", timestamp, jsonTimestamp);
                return false;
            }
            // 将body 和 jsonBody 都转换成 JSONObject 并比较其中的字段是否相同，值是否相同
            JSONObject jsonBodyObject = JSON.parseObject(jsonBody);
            JSONObject bodyObject = JSON.parseObject(body);

            if (!isJsonEqualsIgnoreArrayOrder(jsonBodyObject, bodyObject)) {
                log.warn("body不匹配: expected={}, actual={}", body, jsonBody);
                return false;
            }
            return true;
        } catch (Exception e) {
            log.error("SM2解密或验证异常: {}", e.getMessage());
            return false;
        }
    }
    private Object encryptData(Object data, String publicKey) {
        return Sm2Util.encryptHex(JSON.toJSONString(data), publicKey);
    }

    private boolean isJsonEqualsIgnoreArrayOrder(Object obj1, Object obj2) {
        // 都是 null
        if (obj1 == null && obj2 == null) {
            return true;
        }
        // 一个 null 一个不是
        if (obj1 == null || obj2 == null) {
            return false;
        }

        // 类型不一样
        if (!obj1.getClass().equals(obj2.getClass())) {
            return false;
        }

        // 如果是 JSONObject
        if (obj1 instanceof JSONObject) {
            JSONObject json1 = (JSONObject) obj1;
            JSONObject json2 = (JSONObject) obj2;

            // 对比 key 集合是否一致
            if (!json1.keySet().equals(json2.keySet())) {
                return false;
            }

            // 递归对比每个 value
            for (String key : json1.keySet()) {
                Object val1 = json1.get(key);
                Object val2 = json2.get(key);
                if (!isJsonEqualsIgnoreArrayOrder(val1, val2)) {
                    return false;
                }
            }
            return true;
        } else if (obj1 instanceof JSONArray) {
            JSONArray arr1 = (JSONArray) obj1;
            JSONArray arr2 = (JSONArray) obj2;

            if (arr1.size() != arr2.size()) {
                return false;
            }

            // 转成 List 后排序
            List<Object> list1 = new ArrayList<>(arr1);
            List<Object> list2 = new ArrayList<>(arr2);

            // 排序（基础类型、对象都能排）
            sortJsonList(list1);
            sortJsonList(list2);

            // 递归对比每一个元素
            for (int i = 0; i < list1.size(); i++) {
                if (!isJsonEqualsIgnoreArrayOrder(list1.get(i), list2.get(i))) {
                    return false;
                }
            }
            return true;
        }

        // 普通值（字符串、数字、布尔、null）直接对比
        else {
            return Objects.equals(obj1, obj2);
        }
    }
    /**
     * 排序 JSON 数组（支持对象、基础类型）
     */
    private void sortJsonList(List<Object> list) {
        list.sort((o1, o2) -> {
            if (o1 == null && o2 == null) return 0;
            if (o1 == null) return -1;
            if (o2 == null) return 1;
            // 转成字符串比较（保证任何类型都能排序）
            return o1.toString().compareTo(o2.toString());
        });
    }

}
