package com.junmp.jyzb.boot.core.handle;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.junmp.jyzb.api.annotation.PostRequest;
import com.junmp.jyzb.api.exception.JYZBAppException;
import com.junmp.jyzb.api.exception.enums.RequestExceptionEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;

/**
 * <pre>
 *
 * 描述：请求参数解密
 * 版本：1.0.0
 * 日期：2024/6/1 08:14
 * 作者：ningzp@junmp.com.cn
 * <br>修改记录
 * <br>修改日期        修改人          修改内容
 *
 * </pre>
 */
@Slf4j
@ControllerAdvice
public class EncryptionRequestBodyAdvice implements RequestBodyAdvice {


    /**
     * 设置条件,这个条件为true才会执行下面的beforeBodyRead方法
     */
    @Override
    public boolean supports(MethodParameter method, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        Annotation[] annotations = method.getAnnotatedElement().getAnnotations();
        for (Annotation annotation : annotations) {
            Class<? extends Annotation> annotationType = annotation.annotationType();
            return PostRequest.class.equals(annotationType);
        }
        return false;
    }

    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMsg, MethodParameter parameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
        Method method = parameter.getMethod();
        if (null != method) {
            PostRequest annotation = method.getAnnotation(PostRequest.class);
            if (null != annotation) {
                if (annotation.requiredEncryption()) {
                    return new HttpInputMessage() {
                        @Override
                        public InputStream getBody() throws IOException {
                            //获取请求的内容
                            InputStream body = inputMsg.getBody();
                            String bodyStr = IoUtil.readUtf8(body);
                            //JSON解析请求中的内容
                            JSONObject jsonObject = null;
                            try {
                                jsonObject = JSON.parseObject(bodyStr);
                            } catch (Exception e) {
                                log.error(StrUtil.format("[解析异常]|请求的内容=>{}，异常信息：{}", bodyStr, e.getMessage()));
                                throw new JYZBAppException(RequestExceptionEnum.ENC_REQUEST_JSON_PARSE_ERROR);
                            }
                            // 获取数据密文
                            String reqDataString = jsonObject.getString("body");

                            if (StrUtil.isBlank(reqDataString)) {
                                // 请求json解析异常
                                throw new JYZBAppException(RequestExceptionEnum.ENC_REQUEST_JSON_PARSE_ERROR);
                            }

                            String reqData = null;
                            try {
                                // 使用aes解密请求的内容
                                reqData = URLDecoder.decode(reqDataString, StandardCharsets.UTF_8.toString());

                                log.info(StrUtil.format("[请求明文数据]|请求参数：{}", reqData));
                            } catch (Exception e) {
                                log.error("[AES解密失败]|数据解析异常信息：{}", e.getMessage());
                                // 解密失败
                                throw new JYZBAppException(RequestExceptionEnum.ENC_REQUEST_JSON_PARSE_ERROR);
                            }
                            return new ByteArrayInputStream(reqData.getBytes(CharsetUtil.CHARSET_UTF_8));
                        }

                        @Override
                        public HttpHeaders getHeaders() {
                            return inputMsg.getHeaders();
                        }
                    };
                }

            }

        }
        return inputMsg;
    }

    @Override
    public Object afterBodyRead(Object body, HttpInputMessage inputMsg, MethodParameter parameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return body;
    }

    @Override
    public Object handleEmptyBody(Object body, HttpInputMessage inputMsg, MethodParameter parameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return body;
    }

}
