package com.njcn.gateway.utils;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ServerWebExchange;


import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author hongawen
 * @version 1.0.0
 * @date 2021年05月25日 11:25
 */
@Slf4j
public class IpUtils {


    private static final String UNKNOWN = "unknown";
    private static final String LOCALHOST_IPV4 = "127.0.0.1";
    private static final String LOCALHOST_IPV6 = "0:0:0:0:0:0:0:1";
    private static final String SEPARATOR = ",";

    private static final String HEADER_X_FORWARDED_FOR = "x-forwarded-for";
    private static final String HEADER_PROXY_CLIENT_IP = "Proxy-Client-IP";
    private static final String HEADER_WL_PROXY_CLIENT_IP = "WL-Proxy-Client-IP";

    private static final int IP_LEN = 15;

    /**
     * 获取用户真实IP地址，不直接使用request.getRemoteAddr();的原因是有可能用户使用了代理软件方式避免真实IP地址,
     * <p>
     * 可是，如果通过了多级反向代理的话，X-Forwarded-For的值并不止一个，而是一串IP值，究竟哪个才是真正的用户端的真实IP呢？
     * 答案是取X-Forwarded-For中第一个非unknown的有效IP字符串。
     * <p>
     * 如：X-Forwarded-For：192.168.1.110, 192.168.1.120, 192.168.1.130,
     * 192.168.1.100
     * <p>
     * 用户真实IP为： 192.168.1.110
     */
    public static String getRealIpAddress(ServerHttpRequest request) {
        HttpHeaders headers = request.getHeaders();
        String ipAddress = headers.getFirst(HEADER_X_FORWARDED_FOR);
        if (StrUtil.isBlankIfStr(ipAddress) || UNKNOWN.equalsIgnoreCase(ipAddress)) {
            ipAddress = headers.getFirst(HEADER_PROXY_CLIENT_IP);
        }
        if (StrUtil.isBlankIfStr(ipAddress) || UNKNOWN.equalsIgnoreCase(ipAddress)) {
            ipAddress = headers.getFirst(HEADER_WL_PROXY_CLIENT_IP);
        }
        if (StrUtil.isBlankIfStr(ipAddress) || UNKNOWN.equalsIgnoreCase(ipAddress)) {
            ipAddress = Optional.ofNullable(request.getRemoteAddress())
                    .map(address -> address.getAddress().getHostAddress())
                    .orElse("");
            if (LOCALHOST_IPV4.equals(ipAddress) || LOCALHOST_IPV6.equals(ipAddress)) {
                // 根据网卡取本机配置的IP
                try {
                    InetAddress inet = InetAddress.getLocalHost();
                    ipAddress = inet.getHostAddress();
                } catch (UnknownHostException e) {
                    log.error("解析请求IP失败,{}", Stream.of(e.getStackTrace()).map(StackTraceElement::toString).collect(Collectors.joining(StrUtil.CRLF)));
                }
            }
        }

        // 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
        if (ipAddress != null && ipAddress.length() > IP_LEN) {
            int index = ipAddress.indexOf(SEPARATOR);
            if (index > 0) {
                ipAddress = ipAddress.substring(0, index);
            }
        }

        String clientIp = request.getHeaders().getFirst("X-Forwarded-For");
        if (clientIp == null || clientIp.isEmpty() || "unknown".equalsIgnoreCase(clientIp)) {
            clientIp = request.getHeaders().getFirst("X-Real-IP");
            if (clientIp == null || clientIp.isEmpty() || "unknown".equalsIgnoreCase(clientIp)) {
                clientIp = request.getRemoteAddress().getAddress().getHostAddress();
            }
        } else {
            // X-Forwarded-For 头可能包含多个 IP，取第一个
            int index = clientIp.indexOf(',');
            if (index > 0) {
                clientIp = clientIp.substring(0, index).trim();
            }
        }
        System.out.println("new------:"+clientIp);
//        System.out.println("old------:"+ipAddress);
        return clientIp;
    }

    /**
     * 获取客户端端口
     */
    public static Integer getPort(ServerHttpRequest request) {
        return request.getRemoteAddress().getPort();
    }

}
