package com.securitycontrol.gateway.filter;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.CryptoException;
import com.securitycontrol.common.core.utils.CommonConstant;
import com.securitycontrol.common.core.utils.StringUtils;
import com.securitycontrol.common.core.utils.aes.AesCbcUtils;
import com.securitycontrol.common.core.utils.aes.MonoUtils;
import com.securitycontrol.common.core.utils.aes.StringHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;

import java.lang.reflect.Field;
import java.net.URI;
import java.security.interfaces.RSAPrivateKey;

/**
 * @Author: meng
 * @Description: RSA实现对请求参数解密
 * @Date: 2023/4/6 15:20
 * @Version: 1.0
 */
@Slf4j
@Component
class RsaDecryptResponseGatewayFilterFactory extends AbstractGatewayFilterFactory {

    @Value("${system.jm}")
    public    boolean AQ_JM;

    public final static String heard_name="decrypt";

    @Override
    public GatewayFilter apply(Object config) {
        return (exchange, chain) -> {
            System.err.println("进入拦截器");
            ServerHttpRequest serverHttpRequest = exchange.getRequest();
            String head= serverHttpRequest.getHeaders().getFirst(heard_name);
            if(StringHelper.isNotEmpty(head)&& heard_name.equals(head)){
                  return chain.filter(exchange);
            }
            if(!AQ_JM){
                return chain.filter(exchange);
            }
            //get请求 默认
            if(HttpMethod.GET.matches(serverHttpRequest.getMethodValue())){//如果是get
                if(exchange.getRequest().getQueryParams().isEmpty()){//如果参数是空的
                    return chain.filter(exchange);
                }else{
                    try{
                        updateRequestParam(exchange);
                    }catch (Exception e){
                        log.error(e.toString(),e);
                        return CommonConstant.buildResponse(exchange, HttpStatus.BAD_REQUEST.value(), "请求参数异常");
                    }
                }
            }
            if (!HttpMethod.POST.matches(serverHttpRequest.getMethodValue())) {//非 post请求
                return chain.filter(exchange);
            }
            byte[] decrypBytes;
            GatewayContext gatewayContext = exchange.getAttribute(GatewayContext.CACHE_GATEWAY_CONTEXT);
            if(StrUtil.isBlank(gatewayContext.getCacheBody())){
                if(!exchange.getRequest().getQueryParams().isEmpty()){
                    try{
                        updateRequestParam(exchange);
                    }catch (Exception e){
                        log.error(e.toString(),e);
                        return CommonConstant.buildResponse(exchange, HttpStatus.BAD_REQUEST.value(), "请求参数异常");
                    }
                }
                //未强制加密
                return chain.filter(exchange);
             //   return CommonConstant.buildResponse(exchange, HttpStatus.BAD_REQUEST.value(), "请求参数不能为空");

            }
            try {
                // 获取request body
                String requestBody = gatewayContext.getCacheBody();
                 String  decryptMsg= AesCbcUtils.decrypt(requestBody);
                gatewayContext.setCacheBody(decryptMsg);
                decrypBytes = decryptMsg.getBytes();
            } catch (Exception e) {
                log.error("数据 解密失败:{}", e);
                return CommonConstant.buildResponse(exchange, HttpStatus.BAD_REQUEST.value(), "数据解密失败");
            }
            // 根据解密后的参数重新构建请求
            DataBufferFactory dataBufferFactory = exchange.getResponse().bufferFactory();
            Flux<DataBuffer> bodyFlux = Flux.just(dataBufferFactory.wrap(decrypBytes));
            ServerHttpRequest newRequest = serverHttpRequest.mutate().uri(serverHttpRequest.getURI()).build();
            newRequest = new ServerHttpRequestDecorator(newRequest) {
                @Override
                public Flux<DataBuffer> getBody() {
                    return bodyFlux;
                }
            };
            // 构建新的请求头
            HttpHeaders headers = new HttpHeaders();
            headers.putAll(exchange.getRequest().getHeaders());
            // 由于修改了传递参数，需要重新设置CONTENT_LENGTH，长度是字节长度，不是字符串长度
            int length = decrypBytes.length;
            headers.remove(HttpHeaders.CONTENT_LENGTH);
            headers.setContentLength(length);
            newRequest = new ServerHttpRequestDecorator(newRequest) {
                @Override
                public HttpHeaders getHeaders() {
                    return headers;
                }
            };
            // 把解密后的数据重置到exchange自定义属性中,在之后的日志GlobalLogFilter从此处获取请求参数打印日志
            exchange.getAttributes().put(GatewayContext.CACHE_GATEWAY_CONTEXT, gatewayContext);
            return chain.filter(exchange.mutate().request(newRequest).build());
        };
    }


    /**
     * 修改前端传的参数
     */
    private void updateRequestParam(ServerWebExchange exchange) throws NoSuchFieldException, IllegalAccessException {
        ServerHttpRequest request = exchange.getRequest();
        URI uri = request.getURI();
        //请求参数
        String query = uri.getQuery();
        //判断是否有加密的参数 这里的约定是 param
        if (StringUtils.isNotBlank(query) && query.contains("params")) {
            String[] split = query.split("=");
            String paramValue = split[1];
            //解密请求参数
            String param =AesCbcUtils.decrypt(paramValue);
            //使用反射强行拿出 URI 的 query
            Field targetQuery = uri.getClass().getDeclaredField("query");
            //授权
            targetQuery.setAccessible(true);
            //重新设置参数
            targetQuery.set(uri, param);
        }
    }



}