package com.nokia.tsl_data.util.logging;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.lang.Nullable;
import org.springframework.util.StopWatch;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import com.nokia.tsl_data.util.logging.entity.RepeatableHttpServletResponseWrapper;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 拦截器--添加堆请求和返回结果的输出，并输出从请求开始到访问结束的时长
 */
@Slf4j
public class RequestLogHandlerInterceptor implements HandlerInterceptor {

    private final ThreadLocal<StopWatch> STOP_WATCH_THREAD_LOCAL = new ThreadLocal<>();

    @Override
    public boolean preHandle(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Object handler)
            throws Exception {
        // 启动一个秒表进行计时
        StopWatch stopWatch = new StopWatch();
        STOP_WATCH_THREAD_LOCAL.set(stopWatch);
        stopWatch.start();
        // 日志添加跟踪id
        MDC.put("traceId", UUID.randomUUID().toString().replace("-", ""));
        // 请求头参数
        Map<String, String> headers = new HashMap<>();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String k = headerNames.nextElement();
            String v = request.getHeader(k);
            headers.put(k, v);
        }
        // 这里要对请求体做一次完整的读取
        String body = StreamUtils.copyToString(request.getInputStream(),
                Charset.forName(request.getCharacterEncoding()));
        log.info("请求地址: {} {},请求参数: {}",
                request.getRequestURL().toString(),
                request.getMethod(),
                StringUtils.trimAllWhitespace(body));
        log.info("请求头: {}", headers);
        return true;
    }

    @Override
    public void afterCompletion(@Nullable HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Object handler,
                                @Nullable Exception ex) {
        RepeatableHttpServletResponseWrapper wrapper = (RepeatableHttpServletResponseWrapper) response;
        if (wrapper != null) {
            String responseString = new String(wrapper.toByteArray());
            responseString = responseString.length() > 1000 ? responseString.substring(0, 1000) : responseString;
            StopWatch stopWatch = STOP_WATCH_THREAD_LOCAL.get();
            stopWatch.stop();
            // 返回结果打印前1000个字符
            log.info("耗时 {} ms, 返回 {}: {}", stopWatch.getTotalTimeMillis(), wrapper.getStatus(), responseString);
            STOP_WATCH_THREAD_LOCAL.remove();
        }
    }
}
