package com.erp.gateway.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.UUID;

@Slf4j
@Component
public class LogFilter implements GlobalFilter, Ordered {

    private static final String REQUEST_START_TIME = "requestStartTime";
    private static final String REQUEST_ID = "requestId";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String requestId = UUID.randomUUID().toString().substring(0, 8);

        // 记录请求开始时间
        exchange.getAttributes().put(REQUEST_START_TIME, System.currentTimeMillis());
        exchange.getAttributes().put(REQUEST_ID, requestId);

        // 构建请求日志
        String requestLog = buildRequestLog(request, requestId);
        log.info(requestLog);

        // 记录响应
        ServerHttpResponse response = exchange.getResponse();
        response.getHeaders().add("X-Request-Id", requestId);

        return chain.filter(exchange)
                .then(Mono.fromRunnable(() -> {
                    Long startTime = exchange.getAttribute(REQUEST_START_TIME);
                    if (startTime != null) {
                        long duration = System.currentTimeMillis() - startTime;
                        String responseLog = buildResponseLog(request, response, requestId, duration);
                        log.info(responseLog);
                    }
                }));
    }

    private String buildRequestLog(ServerHttpRequest request, String requestId) {
        return String.format(
                "[%s] %s %s %s | Trace: %s | IP: %s",
                requestId,
                request.getMethod(),
                request.getURI().getPath(),
                request.getQueryParams().isEmpty() ? "" : "?" + request.getQueryString(),
                getHeaderValue(request, "X-Trace-Id"),
                getClientIp(request)
        );
    }

    private String buildResponseLog(ServerHttpRequest request, ServerHttpResponse response,
                                     String requestId, long duration) {
        return String.format(
                "[%s] %s %s | Status: %s | Duration: %dms",
                requestId,
                request.getMethod(),
                request.getURI().getPath(),
                response.getStatusCode(),
                duration
        );
    }

    private String getHeaderValue(ServerHttpRequest request, String header) {
        String value = request.getHeaders().getFirst(header);
        return value != null ? value : "-";
    }

    private String getClientIp(ServerHttpRequest request) {
        String[] headers = {
                "X-Forwarded-For",
                "X-Real-IP",
                "Proxy-Client-IP",
                "WL-Proxy-Client-IP"
        };

        for (String header : headers) {
            String ip = request.getHeaders().getFirst(header);
            if (StringUtils.hasText(ip) && !"unknown".equalsIgnoreCase(ip)) {
                return ip.split(",")[0].trim();
            }
        }

        return request.getRemoteAddress() != null
                ? request.getRemoteAddress().getAddress().getHostAddress()
                : "unknown";
    }

    @Override
    public int getOrder() {
        return -90;
    }
}
