package com.bonus.gateway.filter;

import com.bonus.common.core.exception.CaptchaException;
import com.bonus.common.core.utils.StringUtils;
import com.bonus.common.core.utils.encryption.AesCbcUtils;
import com.bonus.common.core.utils.global.CommonConstant;
import com.bonus.common.core.utils.global.SystemGlobal;
import com.bonus.gateway.module.GatewayContext;
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.RequestPath;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;

import java.lang.reflect.Field;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;

/**
 * 参数自动解密
 * 拦截
 */
@Slf4j
@Component
public class AecDecryptParamFilter extends AbstractGatewayFilterFactory {

    @Value("${system.jie-enable}")
    public    boolean jaData;

    public final static String HEARD_NAME="decrypt";

    /**忽略加密的参数的请求*/
    public static List<String> ignoreUrls = new ArrayList<>();

    {
        ignoreUrls.add("/tcp/ball/xmlAnalysis");
    }

    @Override
    public GatewayFilter apply(Object config) {
        return (exchange, chain) -> {
            ServerHttpRequest serverHttpRequest = exchange.getRequest();
            String head= serverHttpRequest.getHeaders().getFirst(HEARD_NAME);
            if(StringUtils.isNotEmpty(head)&& HEARD_NAME.equals(head)){
                return chain.filter(exchange);
            }
            String reqPath = serverHttpRequest.getURI().getPath();
            boolean sf = ignoreUrls.contains(reqPath);
            if(sf){
                return chain.filter(exchange);
            }
            if(!jaData){
                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);
                        return chain.filter(exchange);
                    }catch (Exception e){
                        log.error(e.toString(),e);
                        return CommonConstant.buildResponse(exchange, HttpStatus.BAD_REQUEST.value(), "请求参数异常");
                    }
                }
            }

            if (HttpMethod.DELETE.matches(serverHttpRequest.getMethodValue())) {
                return chain.filter(exchange);
            }
            HttpHeaders heard=serverHttpRequest.getHeaders();
            if(heard!=null){
                Object object=heard.getFirst("Content-Type");
                if(object!=null){
                    String  contentType=object.toString();
                    if (contentType.contains(MULTIPART_FORM_DATA_VALUE)){
                        return chain.filter(exchange);
                    }
                }
            }

            byte[] decrypBytes;
            GatewayContext gatewayContext = exchange.getAttribute(GatewayContext.CACHE_GATEWAY_CONTEXT);
            if(StringUtils.isEmpty(gatewayContext.getCacheBody())){
                if(!exchange.getRequest().getQueryParams().isEmpty()){
                    try{
                        updateRequestParam(exchange);
                        return chain.filter(exchange);
                    }catch (Exception e){
                        log.error(e.toString(),e);
                        return CommonConstant.buildResponse(exchange, HttpStatus.BAD_REQUEST.value(), "请输入正确的请求参数");
                    }
                }
                //强制加密
              //  return CommonConstant.buildResponse(exchange, HttpStatus.BAD_REQUEST.value(), "请求参数不正确!");
                //未强制加密
                return chain.filter(exchange);
            }
            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, 201, "请求参数不正确!");
            }
            // 根据解密后的参数重新构建请求
            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();
        if (StringUtils.isNotBlank(query)) {
            //解密请求参数
            String param =AesCbcUtils.decrypt(query);
            if(StringUtils.isEmpty(param)){
                throw new CaptchaException("请求参数不正确");
            }
            //使用反射强行拿出 URI 的 query
            Field targetQuery = uri.getClass().getDeclaredField("query");
            //授权
            targetQuery.setAccessible(true);
            //重新设置参数
            targetQuery.set(uri, param);

        }
    }


}
