package com.ruoyi.common.filter;

import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.constant.EncryptConstants;
import com.ruoyi.common.constant.SM4Constants;
import com.ruoyi.common.utils.EncryptHttpServletRequestWrapper;
import com.ruoyi.common.utils.EncryptHttpServletResponseWrapper;
import com.ruoyi.common.utils.SM4Utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.client.RestTemplate;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 请求包装过滤器 - 处理请求解密和包装
 */
@Component
@Slf4j
public class RequestWrapperFilter implements Filter {

    private static final ObjectMapper objectMapper = new ObjectMapper();
    private final PathMatcher pathMatcher = new AntPathMatcher();
    private final RestTemplate restTemplate = new RestTemplate();

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        // 检查是否开启加解密功能
        if (!EncryptConstants.ENCRYPT_ENABLED) {
            chain.doFilter(request, response);
            return;
        }

        // 检查是否是SSE流式响应 - 不处理
        if (isSseResponse(httpRequest, httpResponse)) {
            chain.doFilter(request, response);
            return;
        }

        // 检查URL是否需要解密
        if (needProcess(httpRequest)) {
            // 处理请求解密
            String method = httpRequest.getMethod();
            if("POST".equalsIgnoreCase(method)) {
                HttpServletRequest processedRequest = processBodyRequest(httpRequest);
                chain.doFilter(processedRequest, response);
            }else{
                EncryptHttpServletResponseWrapper responseWrapper = new EncryptHttpServletResponseWrapper(httpResponse);
                String forwardUrl = buildGetRequestURI(httpRequest);
                if (StringUtils.isNotBlank(forwardUrl)) {
                    log.info("GET请求解密后转发URL：{}", forwardUrl);
                    // 服务器内部转发
                    request.setAttribute("ENCRYPT_PROCESSED", Boolean.TRUE);
                    RequestDispatcher dispatcher = request.getRequestDispatcher(forwardUrl);
                    dispatcher.forward(request, responseWrapper);

                    // 2. 监听/处理转发后的响应（核心逻辑：从包装器中获取响应数据）
                    byte[] content = responseWrapper.getContent();
                    String originalResponse = new String(content, StandardCharsets.UTF_8);
                    if (StringUtils.isNotBlank(originalResponse) && !originalResponse.trim().isEmpty()) {
                        String encryptedResponse = SM4Utils.encryptEcb(SM4Constants.SM4_KET, originalResponse);

                        // 构建加密响应
                        Map<String, Object> result = new HashMap<>();
                        result.put("encrypted", true);
                        result.put("encryptedData", encryptedResponse);
                        result.put("timestamp", System.currentTimeMillis());

                        String finalResponse = objectMapper.writeValueAsString(result);

                        // 设置响应
                        byte[] encryptedBytes = finalResponse.getBytes(StandardCharsets.UTF_8);
                        httpResponse.setContentLength(encryptedBytes.length);
                        httpResponse.setContentType("application/json;charset=UTF-8");
                        httpResponse.getOutputStream().write(encryptedBytes);
                    } else {
                        // 空响应直接返回空
                        httpResponse.getOutputStream().write(new byte[0]);
                    }
                    return;
                } else {
                    chain.doFilter(request, response);
                }
            }
        } else {
            // 不需要解密，直接放行
            chain.doFilter(request, response);
        }
    }

    /**
     * 判断请求是否需要处理
     */
    private boolean needProcess(HttpServletRequest request) {
        if (Boolean.TRUE.equals(request.getAttribute("ENCRYPT_PROCESSED"))) {
            return false;
        }

        String requestURI = request.getRequestURI();

        // 检查URL是否匹配需要加解密的模式
        for (String pattern : EncryptConstants.URL_PATTERNS) {
            if (pathMatcher.match(pattern, requestURI)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 判断是否是SSE流式响应
     */
    private boolean isSseResponse(HttpServletRequest request, HttpServletResponse response) {
        String path = request.getRequestURI();
        String method = request.getMethod();

        // 检查是否是聊天接口
        if ("/app/chat/chat".equals(path) && "POST".equalsIgnoreCase(method)) {
            return true;
        }

        // 检查Accept头是否包含text/event-stream
        String acceptHeader = request.getHeader("Accept");
        if (acceptHeader != null && acceptHeader.contains("text/event-stream")) {
            return true;
        }

        // 检查响应头是否已经设置为text/event-stream
        String contentType = response.getContentType();
        if (contentType != null && contentType.contains("text/event-stream")) {
            return true;
        }

        return false;
    }

    private HttpServletRequest processBodyRequest(HttpServletRequest request) throws IOException {
        String body = getRequestBody(request);
        log.info("过滤器 - 原始请求体: " + body);

        if (StringUtils.isNotBlank(body)) {
            try {
                // 解析请求体，提取encryptedData字段
                JsonNode jsonNode = objectMapper.readTree(body);
                JsonNode encryptedDataNode = jsonNode.get("encryptedData");

                if (encryptedDataNode != null && encryptedDataNode.isTextual()) {
                    String encryptedData = encryptedDataNode.asText();
                    // 解密 encryptedData
                    String decryptedData = SM4Utils.decryptEcb(SM4Constants.SM4_KET, encryptedData);

                    // 使用解密后的数据创建包装请求
                    return new EncryptHttpServletRequestWrapper(request, decryptedData);
                } else {
                    log.info("请求体中未找到encryptedData字段，直接返回原始请求");
                    return request;
                }
            } catch (Exception e) {
                log.error("POST请求体解密失败: " + e.getMessage());
                // 解密失败时返回原始请求，让业务层处理
                return request;
            }
        }
        return request;
    }

    private String getRequestBody(HttpServletRequest request) throws IOException {
        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader bufferedReader = null;
        try {
            InputStream inputStream = request.getInputStream();
            if (inputStream != null) {
                bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                char[] charBuffer = new char[128];
                int bytesRead;
                while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                    stringBuilder.append(charBuffer, 0, bytesRead);
                }
            }
        } finally {
            if (bufferedReader != null) {
                bufferedReader.close();
            }
        }
        return stringBuilder.toString();
    }

    private String buildGetRequestURI(HttpServletRequest request) {
        String baseUrl = request.getRequestURI(); // 完整基础URL
        String encryptedData = request.getParameter("encryptedData");

        if (StringUtils.isBlank(encryptedData)) {
            log.info("GET请求未携带encryptedData参数，返回原始URL");
            return null; // 无加密参数，不处理
        }

        try {
            // 解密参数（增加异常捕获，避免解密失败导致URL拼接异常）
            String decryptedData = SM4Utils.decryptEcb(SM4Constants.SM4_KET, encryptedData);
            if (StringUtils.isBlank(decryptedData)) {
                log.error("GET请求encryptedData解密后为空");
                return null;
            }

            JSONObject object = JSONObject.parseObject(decryptedData);
            if (object.isEmpty()) {
                log.info("解密后的参数为空，返回原始URL");
                return null;
            }

            // 拼接参数（用StringBuilder，避免字符串频繁拼接）
            StringBuilder params = new StringBuilder();
            for (Map.Entry<String, Object> entry : object.entrySet()) { // 用entrySet更高效
                String key = entry.getKey();
                Object value = entry.getValue();

                // 跳过空值和空key
                if (StringUtils.isBlank(key) || Objects.isNull(value)) {
                    continue;
                }

                // 处理参数值：数组/嵌套JSON转为JSON字符串，普通类型直接转字符串
                String paramValue = String.valueOf(value);

                // URL编码（处理中文、特殊字符，如空格、&、=等）
                String encodedValue = URLEncoder.encode(paramValue, "UTF-8");
                if (params.length() > 0) {
                    params.append("&");
                }
                params.append(key).append("=").append(encodedValue);
            }

            // 拼接完整URL（仅当有参数时才加?）
            if (params.length() > 0) {
                return baseUrl + "?" + params.toString();
            } else {
                log.info("解密后的参数均为空，返回原始URL");
                return null;
            }

        } catch (Exception e) {
            log.error("GET请求参数解密/拼接失败", e);
            return null; // 异常时返回null，走原始请求
        }
    }
}