package com.hzs.common.core.filter;

import cn.hutool.json.JSONTokener;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hzs.common.core.utils.StringJsonUtils;
import com.hzs.common.core.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * description: 自定义TrimRequestWrapper类
 * @author: sui q
 * @time: 2023/4/3 14:10
 * @classname: TrimRequestWrapper
 * @package_name: com.hzs.gateway.config
 * version 1.0.0
 */
@Slf4j
public class TrimRequestWrapper extends HttpServletRequestWrapper {

    /**
     * 保存处理后的参数
     */
    private Map<String, String[]> params = new HashMap<>();


    public TrimRequestWrapper(HttpServletRequest request) {
        // 将request交给父类，以便于调用对应方法的时候，将其输出，其实父亲类的实现方式和第一种new的方式类似
        super(request);
        //将参数表，赋予给当前的Map以便于持有request中的参数
        Map<String, String[]> requestMap=request.getParameterMap();
        log.info("转化前参数："+JSON.toJSONString(requestMap));
        this.params.putAll(requestMap);
        this.modifyParameterValues();
        log.info("转化后参数："+JSON.toJSONString(params));
    }

    /**
     * 将parameter的值去除空格后重写回去
     */
    public void modifyParameterValues() {
        Set<String> set = params.keySet();
        for (String key : set) {
            String[] values = params.get(key);
            values[0] = values[0].trim();
            params.put(key, values);
        }

    }

    /**
     * 重写getParameter 参数从当前类中的map获取
     */
    @Override
    public String getParameter(String name) {
        String[] values = params.get(name);
        if (values == null || values.length == 0) {
            return null;
        }
        return values[0];
    }

    /**
     * 重写getParameterValues
     */
    @Override
    public String[] getParameterValues(String name) {
        return params.get(name);
    }

    /**
     * 重写getInputStream方法  post类型的请求参数必须通过流才能获取到值
     * 这种获取的参数的方式针对于内容类型为文本类型，比如Content-Type:text/plain,application/json,text/html等
     * 在springmvc中可以使用@RequestBody 来获取 json数据类型
     * 其他文本类型不做处理，重点处理json数据格式
     * getInputStream() ，只有当方法为post请求，且参数为json格式是，会被默认调用
     */
    @Override
    public ServletInputStream getInputStream() throws IOException {
        //
        if (!super.getHeader(HttpHeaders.CONTENT_TYPE).equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE) &&
                !super.getHeader(HttpHeaders.CONTENT_TYPE).equalsIgnoreCase(MediaType.APPLICATION_JSON_UTF8_VALUE)) {
            //如果参数不是json格式则直接返回
            return super.getInputStream();
        }
        //为空，直接返回
        String json = IOUtils.toString(super.getInputStream(), "utf-8");
        if (StringUtils.isEmpty(json)) {
            return super.getInputStream();
        }
        log.info("转化前参数："+json);
        ObjectMapper objectMapper  =  new  ObjectMapper();
        JsonNode jsonNode = objectMapper.readTree(json);
        ByteArrayInputStream bis;
        if(jsonNode.isObject()){
            Map<String,Object> map= StringJsonUtils.jsonObjectStrTrim(json);
            log.info("转化后参数："+JSON.toJSONString(map));
            bis = new ByteArrayInputStream(JSON.toJSONString(map).getBytes("utf-8"));
        }else {
            JSONArray jsonArray = StringJsonUtils.jsonArrayStrTrim(json);
            log.info("转化后参数："+ jsonArray.toString());
            bis = new ByteArrayInputStream(jsonArray.toString().getBytes("utf-8"));
        }
        return new TrimServletInputStream(bis);
    }

    class TrimServletInputStream extends  ServletInputStream{
        private ByteArrayInputStream bis;
        public TrimServletInputStream(ByteArrayInputStream bis){
            this.bis=bis;
        }
        @Override
        public boolean isFinished() {
            return true;
        }

        @Override
        public boolean isReady() {
            return true;
        }

        @Override
        public void setReadListener(ReadListener listener) {

        }
        @Override
        public int read(){
            return bis.read();
        }
    }
}
