package com.qmth.boot.api.utils;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.qmth.boot.api.config.ApiProperties;
import com.qmth.boot.core.security.model.AccessEntity;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * HTTP请求/返回数据跟踪日志
 */
public class HttpTraceUtil {

    private static final Logger log = LoggerFactory.getLogger(HttpTraceUtil.class);

    private boolean enable;

    private String prefix;

    public HttpTraceUtil(ApiProperties apiProperties) {
        this.enable = apiProperties.isHttpTrace();
        this.prefix = apiProperties.getUriPrefix();
    }

    public void request(HttpServletRequest request, MethodSignature method, Object[] args) {
        this.enable = this.enable && request.getServletPath().startsWith(prefix);
        if (this.enable) {
            try {
                Map<String, Object> content = new LinkedHashMap<>();
                content.put("uri", request.getServletPath());
                content.put("method", request.getMethod());
                content.put("content-type", request.getContentType());
                Map<String, Object> parameter = new HashMap<>();
                if (ArrayUtils.isNotEmpty(method.getParameterNames())) {
                    for (int i = 0; i < method.getParameterNames().length; i++) {
                        filter(parameter, method.getParameterNames()[i], args[i]);
                    }
                }
                content.put("parameter", parameter);
                // 记录日志
                log.info("Request info: \n{}",
                        new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(content));
            } catch (Exception e) {
                log.error("Trace request error", e);
            }
        }
    }

    private void filter(Map<String, Object> parameter, String name, Object value) {
        if (value instanceof HttpServletRequest || value instanceof HttpServletResponse
                || value instanceof AccessEntity) {
            return;
        } else if (value instanceof MultipartFile) {
            MultipartFile file = (MultipartFile) value;
            Map<String, Object> map = new HashMap<>();
            map.put("class", value.getClass().getSimpleName());
            map.put("name", file.getName());
            map.put("size", file.getSize());
            parameter.put(name, map);
        } else {
            parameter.put(name, value);
        }
    }

    public Object response(Object result) {
        if (this.enable) {
            try {
                log.info("Response body: \n{}", new ObjectMapper().writerWithDefaultPrettyPrinter()
                        .writeValueAsString(result != null ? result : "null"));
            } catch (Exception e) {
                log.error("Trace response error", e);
            }
        }
        return result;
    }
}
