package org.wcs.serve.filter;

import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.wcs.mapper.intf.AppRecordApiResponseService;
import org.wcs.model.po.app.AppRecordApiResponse;
import org.wcs.utils.AppTimeUtils;
import org.wcs.utils.AppUUIDUtils;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;

@Slf4j
@Component
@WebFilter(filterName = "pubLoggerFilter")
@RequiredArgsConstructor
public class PubLoggerFilter extends HttpFilter {

    private final AppRecordApiResponseService apiResponseService;

    @Override
    protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        String uri = request.getRequestURI(); // 资源地址
        /* pub 接口过滤事件 */
        if(uri.matches("^/.*/api/pub/.*")) {
            String method = request.getMethod(); // 请求方法
            // Wrapper封装request和response
            ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
            ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
            LocalDateTime startTime = LocalDateTime.now();
            Exception exception = null;
            // 继续执行请求链
            try {
                chain.doFilter(requestWrapper, responseWrapper);
            } catch (Exception e) {
                exception = e;
            }
            LocalDateTime endTime = LocalDateTime.now();
            String queryString = request.getQueryString(); // 请求URL参数
            String remoteHost = request.getRemoteHost(); // 客户端主机名
            String remoteAddr = request.getRemoteAddr(); // 客户端ip地址
            String contentType = request.getContentType(); // 请求类型
            int status = response.getStatus(); // 响应状态
            byte[] requestContent = requestWrapper.getContentAsByteArray(); // 请求体
            byte[] responseContent = responseWrapper.getContentAsByteArray(); // 响应体
            String requestContentString = new String(requestContent).replaceAll("\\s*", ""); // 请求数据
            String responseContentString = new String(responseContent).replaceAll("\\s*", ""); // 响应数据
            // 构造请求记录
            String requestId = AppUUIDUtils.getNewUUID();
            StringBuilder requestLogBuilder = new StringBuilder();
            requestLogBuilder.append("外部系统请求：").append("\n");
            requestLogBuilder.append("请求时间：").append(AppTimeUtils.formatLocalDatetime(startTime)).append("\n");
            requestLogBuilder.append("请求ID：").append(requestId).append("\n");
            requestLogBuilder.append("请求地址：").append(uri).append("\n");
            requestLogBuilder.append("请求方法：").append(method).append("\n");
            requestLogBuilder.append("请求参数：").append(queryString).append("\n");
            requestLogBuilder.append("客户端：").append(remoteHost).append("(").append(remoteAddr).append(")").append("\n");
            requestLogBuilder.append("请求头：").append("\n");
            requestLogBuilder.append("请求类型：").append(contentType).append("\n");
            requestLogBuilder.append("请求数据：").append(requestContentString).append("\n");
            requestLogBuilder.append("响应状态：").append(status).append("\n");
            requestLogBuilder.append("响应数据：").append(responseContentString).append("\n");
            requestLogBuilder.append("结束时间：").append(AppTimeUtils.formatLocalDatetime(endTime)).append("\n");
            long useTime = Duration.between(startTime, endTime).toMillis();
            requestLogBuilder.append("请求耗时：").append(useTime).append("\n");
            if(exception != null) {
                requestLogBuilder.append("异常信息：").append(exception).append("\n");
            }
            log.info(requestLogBuilder.toString());
            // GET 请求只记录文本日志，其他请求插入数据库并记录文本日志
            if(!method.equalsIgnoreCase("GET")) {
                AppRecordApiResponse appRecordApiResponse = new AppRecordApiResponse();
                appRecordApiResponse.setRecordId(requestId);
                appRecordApiResponse.setPath(uri);
                appRecordApiResponse.setMethod(method);
                appRecordApiResponse.setUrlParam(queryString);
                appRecordApiResponse.setResponseCode(status);
                appRecordApiResponse.setMediaType(contentType);
                appRecordApiResponse.setClientAddress(remoteAddr);
                appRecordApiResponse.setHeader("");
                appRecordApiResponse.setRequestTime(startTime);
                appRecordApiResponse.setResponseTime(endTime);
                appRecordApiResponse.setUseTime(BigDecimal.valueOf(useTime));
                appRecordApiResponse.setRequestMsg(requestContentString);
                appRecordApiResponse.setResponseMsg(responseContentString);
                appRecordApiResponse.setCookie("");
                appRecordApiResponse.setErrMsg(exception == null ? "" : exception.getMessage());
                apiResponseService.insert(appRecordApiResponse);
            }
            // 把缓存的响应数据，响应给客户端
            responseWrapper.copyBodyToResponse();
        } else {
            chain.doFilter(request, response);
        }
    }

}
