package com.ruoyi.credit.interceptor;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

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;

import com.ruoyi.common.utils.StringUtils;

/**
 * IP白名单拦截器
 * 
 * 实现基于IP地址的访问控制，只允许白名单中的IP访问特定API
 * 
 * @author ruoyi
 * @date 2025-12-19
 */
@Component
public class IpWhitelistInterceptor implements HandlerInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(IpWhitelistInterceptor.class);

    @Value("${api.ipWhitelist.enabled:true}")
    private Boolean ipWhitelistEnabled;

    @Value("${api.ipWhitelist.allowedIps:127.0.0.1,::1}")
    private String allowedIpsConfig;

    // 需要IP白名单验证的API路径前缀
    private static final String[] WHITELIST_REQUIRED_PATHS = {
        "/api/credit/financing",
        "/api/payment/escrow",
        "/api/blockchain",
        "/api/security"
    };

    private Set<String> allowedIps;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 安全优先：如果配置未正确加载，默认启用IP白名单验证
        boolean isIpWhitelistEnabled = (ipWhitelistEnabled != null) ? ipWhitelistEnabled : true;
        
        if (!isIpWhitelistEnabled) {
            return true;
        }

        String requestPath = request.getRequestURI();
        
        // 检查是否需要IP白名单验证
        if (!requiresIpWhitelistVerification(requestPath)) {
            return true;
        }

        // 初始化允许的IP列表
        if (allowedIps == null) {
            initializeAllowedIps();
        }

        String clientIp = getClientIpAddress(request);
        
        if (!isIpAllowed(clientIp)) {
            logger.warn("IP访问被拒绝: IP={}, URI={}", clientIp, requestPath);
            
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"code\":403,\"msg\":\"访问被拒绝：IP地址不在白名单中\"}");
            
            return false;
        }

        logger.debug("IP白名单验证通过: IP={}, URI={}", clientIp, requestPath);
        return true;
    }

    /**
     * 检查请求路径是否需要IP白名单验证
     */
    private boolean requiresIpWhitelistVerification(String requestPath) {
        return Arrays.stream(WHITELIST_REQUIRED_PATHS)
                .anyMatch(requestPath::startsWith);
    }

    /**
     * 初始化允许的IP列表
     */
    private void initializeAllowedIps() {
        allowedIps = new HashSet<>();
        
        if (StringUtils.isNotEmpty(allowedIpsConfig)) {
            String[] ips = allowedIpsConfig.split(",");
            for (String ip : ips) {
                String trimmedIp = ip.trim();
                if (StringUtils.isNotEmpty(trimmedIp)) {
                    allowedIps.add(trimmedIp);
                }
            }
        }
        
        // 默认允许本地访问
        allowedIps.add("127.0.0.1");
        allowedIps.add("::1");
        allowedIps.add("0:0:0:0:0:0:0:1");
        
        logger.info("IP白名单已初始化，允许的IP数量: {}", allowedIps.size());
    }

    /**
     * 检查IP是否在白名单中
     */
    private boolean isIpAllowed(String clientIp) {
        if (allowedIps.contains(clientIp)) {
            return true;
        }

        // 检查IP段匹配（支持CIDR格式，简化实现）
        for (String allowedIp : allowedIps) {
            if (allowedIp.contains("/")) {
                // CIDR格式的IP段
                if (isIpInCidrRange(clientIp, allowedIp)) {
                    return true;
                }
            } else if (allowedIp.contains("*")) {
                // 通配符格式的IP段
                if (isIpMatchWildcard(clientIp, allowedIp)) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * 检查IP是否在CIDR范围内（简化实现）
     */
    private boolean isIpInCidrRange(String clientIp, String cidrRange) {
        try {
            String[] parts = cidrRange.split("/");
            if (parts.length != 2) {
                return false;
            }

            String networkIp = parts[0];
            int prefixLength = Integer.parseInt(parts[1]);

            // 简化实现：只处理IPv4的常见情况
            if (prefixLength == 24) {
                // /24 网段
                String clientNetwork = clientIp.substring(0, clientIp.lastIndexOf('.'));
                String allowedNetwork = networkIp.substring(0, networkIp.lastIndexOf('.'));
                return clientNetwork.equals(allowedNetwork);
            } else if (prefixLength == 16) {
                // /16 网段
                String[] clientParts = clientIp.split("\\.");
                String[] allowedParts = networkIp.split("\\.");
                return clientParts[0].equals(allowedParts[0]) && clientParts[1].equals(allowedParts[1]);
            }
        } catch (Exception e) {
            logger.warn("CIDR范围解析失败: {}", cidrRange, e);
        }

        return false;
    }

    /**
     * 检查IP是否匹配通配符模式
     */
    private boolean isIpMatchWildcard(String clientIp, String wildcardPattern) {
        try {
            String regex = wildcardPattern.replace(".", "\\.")
                                        .replace("*", "\\d+");
            return clientIp.matches(regex);
        } catch (Exception e) {
            logger.warn("通配符模式匹配失败: {}", wildcardPattern, e);
            return false;
        }
    }

    /**
     * 获取客户端IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        // 检查是否通过代理
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (StringUtils.isNotEmpty(xForwardedFor)) {
            // X-Forwarded-For可能包含多个IP，取第一个
            String[] ips = xForwardedFor.split(",");
            return ips[0].trim();
        }

        // 检查其他代理头
        String xRealIp = request.getHeader("X-Real-IP");
        if (StringUtils.isNotEmpty(xRealIp)) {
            return xRealIp.trim();
        }

        String xOriginalForwardedFor = request.getHeader("X-Original-Forwarded-For");
        if (StringUtils.isNotEmpty(xOriginalForwardedFor)) {
            return xOriginalForwardedFor.trim();
        }

        // 直接连接的IP
        return request.getRemoteAddr();
    }

    /**
     * 动态添加IP到白名单
     */
    public void addIpToWhitelist(String ip) {
        if (allowedIps == null) {
            initializeAllowedIps();
        }
        allowedIps.add(ip);
        logger.info("IP已添加到白名单: {}", ip);
    }

    /**
     * 动态移除IP从白名单
     */
    public void removeIpFromWhitelist(String ip) {
        if (allowedIps != null) {
            allowedIps.remove(ip);
            logger.info("IP已从白名单移除: {}", ip);
        }
    }

    /**
     * 获取当前白名单
     */
    public Set<String> getAllowedIps() {
        if (allowedIps == null) {
            initializeAllowedIps();
        }
        return new HashSet<>(allowedIps);
    }
}