package com.starry.common.interceptor;

import com.alibaba.fastjson2.JSON;
import java.util.Collections;
import java.util.Map;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

/**
 * 请求响应日志拦截器
 * 记录HTTP请求和响应的详细信息，用于调试和监控
 *
 * @author Claude
 */
@Component
public class RequestLoggingInterceptor implements HandlerInterceptor {

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

    private static final String START_TIME_ATTRIBUTE = "startTime";
    public static final String BUSINESS_RESULT_ATTRIBUTE = "requestLoggingBusinessResult";

    @Value("${logging.business-error-as-warn:false}")
    private boolean businessErrorAsWarn;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        long startTime = System.currentTimeMillis();
        request.setAttribute(START_TIME_ATTRIBUTE, startTime);

        // 记录请求开始
        logRequestStart(request);

        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                              Object handler, Exception ex) throws Exception {

        Long startTime = (Long) request.getAttribute(START_TIME_ATTRIBUTE);
        long duration = startTime != null ? System.currentTimeMillis() - startTime : 0;

        // 记录请求完成
        logRequestCompletion(request, response, duration, ex);
    }

    /**
     * 记录请求开始信息
     */
    private void logRequestStart(HttpServletRequest request) {
        try {
            String method = request.getMethod();
            String uri = request.getRequestURI();
            String queryString = request.getQueryString();
            String remoteAddr = getClientIpAddress(request);
            String userAgent = request.getHeader("User-Agent");

            // 构建完整URL
            String fullUrl = uri;
            if (queryString != null && !queryString.isEmpty()) {
                fullUrl += "?" + queryString;
            }

            log.info("Request started: {} {} from {} [{}]",
                    method, fullUrl, remoteAddr, getUserAgentInfo(userAgent));

            // 记录请求头（过滤敏感信息）
            Map<String, String> headers = Collections.list(request.getHeaderNames())
                    .stream()
                    .filter(this::isSafeHeader)
                    .collect(Collectors.toMap(
                            name -> name,
                            request::getHeader
                    ));

            if (!headers.isEmpty()) {
                log.debug("Request headers: {}", JSON.toJSONString(headers));
            }

        } catch (Exception e) {
            log.warn("Error logging request start: {}", e.getMessage());
        }
    }

    /**
     * 记录请求完成信息
     */
    private void logRequestCompletion(HttpServletRequest request, HttpServletResponse response,
                                    long duration, Exception ex) {
        try {
            String method = request.getMethod();
            String uri = request.getRequestURI();
            int status = response.getStatus();
            String statusText = getStatusText(status);

            BusinessResult businessResult = (BusinessResult) request.getAttribute(BUSINESS_RESULT_ATTRIBUTE);
            if (businessResult != null) {
                request.removeAttribute(BUSINESS_RESULT_ATTRIBUTE);
            }

            if (ex != null) {
                log.error("Request completed with error: {} {} - {} {} ({}ms) - Exception: {}",
                        method, uri, status, statusText, duration, ex.getMessage());
            } else if (businessResult != null) {
                logWithBusinessResult(method, uri, status, statusText, duration, businessResult);
            } else if (status >= 400) {
                log.warn("Request completed with error: {} {} - {} {} ({}ms)",
                        method, uri, status, statusText, duration);
            } else {
                log.info("Request completed: {} {} - {} {} ({}ms)",
                        method, uri, status, statusText, duration);
            }

            // 记录响应头（过滤敏感信息）
            if (log.isDebugEnabled()) {
                Map<String, String> responseHeaders = response.getHeaderNames()
                        .stream()
                        .filter(this::isSafeHeader)
                        .collect(Collectors.toMap(
                                name -> name,
                                response::getHeader,
                                (existing, replacement) -> existing // Keep first value if duplicate keys
                        ));

                if (!responseHeaders.isEmpty()) {
                    log.debug("Response headers: {}", JSON.toJSONString(responseHeaders));
                }
            }

        } catch (Exception e) {
            log.warn("Error logging request completion: {}", e.getMessage());
        }
    }

    /**
     * 获取客户端真实IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        String[] headerNames = {
                "X-Forwarded-For",
                "X-Real-IP",
                "Proxy-Client-IP",
                "WL-Proxy-Client-IP",
                "HTTP_CLIENT_IP",
                "HTTP_X_FORWARDED_FOR"
        };

        for (String headerName : headerNames) {
            String ip = request.getHeader(headerName);
            if (ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) {
                // X-Forwarded-For可能包含多个IP，取第一个
                if (ip.contains(",")) {
                    ip = ip.substring(0, ip.indexOf(",")).trim();
                }
                return ip;
            }
        }

        return request.getRemoteAddr();
    }

    /**
     * 简化User-Agent信息
     */
    private String getUserAgentInfo(String userAgent) {
        if (userAgent == null || userAgent.isEmpty()) {
            return "Unknown";
        }

        if (userAgent.contains("WeChat")) {
            return "WeChat";
        } else if (userAgent.contains("Chrome")) {
            return "Chrome";
        } else if (userAgent.contains("Safari")) {
            return "Safari";
        } else if (userAgent.contains("Firefox")) {
            return "Firefox";
        } else if (userAgent.contains("PostmanRuntime")) {
            return "Postman";
        } else {
            return "Other";
        }
    }

    /**
     * 获取HTTP状态码描述
     */
    private String getStatusText(int status) {
        if (status >= 200 && status < 300) {
            return "OK";
        } else if (status >= 300 && status < 400) {
            return "Redirect";
        } else if (status >= 400 && status < 500) {
            return "Client Error";
        } else if (status >= 500) {
            return "Server Error";
        } else {
            return "Unknown";
        }
    }

    private void logWithBusinessResult(String method, String uri, int status, String statusText,
                                       long duration, BusinessResult businessResult) {
        String template = "Request completed: {} {} - {} {} ({}ms) businessCode={} success={} message={}";
        if (isBusinessError(businessResult)) {
            if (businessErrorAsWarn) {
                log.warn(template, method, uri, status, statusText, duration,
                        businessResult.getCode(), businessResult.isSuccess(), businessResult.getMessage());
            } else {
                log.error(template, method, uri, status, statusText, duration,
                        businessResult.getCode(), businessResult.isSuccess(), businessResult.getMessage());
            }
        } else if (isBusinessWarn(businessResult)) {
            log.warn(template, method, uri, status, statusText, duration,
                    businessResult.getCode(), businessResult.isSuccess(), businessResult.getMessage());
        } else {
            log.info(template, method, uri, status, statusText, duration,
                    businessResult.getCode(), businessResult.isSuccess(), businessResult.getMessage());
        }
    }

    private boolean isBusinessError(BusinessResult businessResult) {
        Integer code = businessResult.getCode();
        return code != null && code >= 500;
    }

    private boolean isBusinessWarn(BusinessResult businessResult) {
        Integer code = businessResult.getCode();
        if (code != null) {
            return code >= 400;
        }
        return !businessResult.isSuccess();
    }

    public static final class BusinessResult {
        private final boolean success;
        private final Integer code;
        private final String message;

        public BusinessResult(boolean success, Integer code, String message) {
            this.success = success;
            this.code = code;
            this.message = message;
        }

        public boolean isSuccess() {
            return success;
        }

        public Integer getCode() {
            return code;
        }

        public String getMessage() {
            return message;
        }
    }

    /**
     * 判断是否为安全的请求头（不包含敏感信息）
     */
    private boolean isSafeHeader(String headerName) {
        String lowerName = headerName.toLowerCase();
        return !lowerName.contains("authorization") &&
               !lowerName.contains("cookie") &&
               !lowerName.contains("password") &&
               !lowerName.contains("token") &&
               !lowerName.contains("secret");
    }
}
