package middleware

import (
	"net"
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/user-management-system/internal/security"
)

// IPFilterConfig IP过滤中间件配置
type IPFilterConfig struct {
	TrustProxy     bool     // 是否信任 X-Forwarded-For
	TrustedProxies []string // 可信代理 IP 列表
}

// IPFilterMiddleware IP 黑白名单过滤中间件
type IPFilterMiddleware struct {
	filter *security.IPFilter
	config IPFilterConfig
}

// NewIPFilterMiddleware 创建 IP 过滤中间件
func NewIPFilterMiddleware(filter *security.IPFilter, config IPFilterConfig) *IPFilterMiddleware {
	return &IPFilterMiddleware{filter: filter, config: config}
}

// Filter 返回 Gin 中间件 HandlerFunc
// 逻辑：先取客户端真实 IP → 检查黑名单 → 被封则返回 403 并终止
func (m *IPFilterMiddleware) Filter() gin.HandlerFunc {
	return func(c *gin.Context) {
		ip := m.realIP(c)

		blocked, reason := m.filter.IsBlocked(ip)
		if blocked {
			c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
				"code":    403,
				"message": "访问被拒绝：" + reason,
			})
			return
		}

		// 将真实 IP 写入 context，供后续中间件和 handler 直接取用
		c.Set("client_ip", ip)
		c.Next()
	}
}

// GetFilter 返回底层 IPFilter，供 handler 层做黑白名单管理
func (m *IPFilterMiddleware) GetFilter() *security.IPFilter {
	return m.filter
}

// realIP 从请求中提取真实客户端 IP
// 优先级：X-Forwarded-For > X-Real-IP > RemoteAddr
// SEC-05 修复：如果启用 TrustProxy，只接受来自可信代理的 X-Forwarded-For
func (m *IPFilterMiddleware) realIP(c *gin.Context) string {
	// 如果不信任代理，直接使用 TCP 连接 IP
	if !m.config.TrustProxy {
		return c.ClientIP()
	}

	// X-Forwarded-For 可能包含代理链
	xff := c.GetHeader("X-Forwarded-For")
	if xff != "" {
		// 从右到左遍历（最右边是最后一次代理添加的）
		for _, part := range strings.Split(xff, ",") {
			ip := strings.TrimSpace(part)
			if ip == "" {
				continue
			}
			// 检查是否是可信代理
			if !m.isTrustedProxy(ip) {
				continue // 不是可信代理，跳过
			}
			// 是可信代理，检查是否为公网 IP
			if !isPrivateIP(ip) {
				return ip
			}
		}
	}

	// X-Real-IP（Nginx 反代常用）
	if xri := c.GetHeader("X-Real-IP"); xri != "" {
		return strings.TrimSpace(xri)
	}

	// 直接 TCP 连接的 RemoteAddr（去掉端口号）
	ip, _, err := net.SplitHostPort(c.Request.RemoteAddr)
	if err != nil {
		return c.Request.RemoteAddr
	}
	return ip
}

// isTrustedProxy 检查 IP 是否在可信代理列表中
func (m *IPFilterMiddleware) isTrustedProxy(ip string) bool {
	if len(m.config.TrustedProxies) == 0 {
		return true // 如果没有配置可信代理列表，默认信任所有（兼容旧行为）
	}
	for _, trusted := range m.config.TrustedProxies {
		if ip == trusted {
			return true
		}
	}
	return false
}

// InternalOnly 限制只有内网 IP 可以访问（用于 /metrics 等运维端点）
// Prometheus scraper 通常部署在同一内网，不需要 JWT 鉴权，但必须限制来源
func InternalOnly() gin.HandlerFunc {
	return func(c *gin.Context) {
		ip := c.ClientIP()
		if !isPrivateIP(ip) {
			c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
				"code":    403,
				"message": "此端点仅限内网访问",
			})
			return
		}
		c.Next()
	}
}

// isPrivateIP 判断是否为内网 IP
func isPrivateIP(ipStr string) bool {
	ip := net.ParseIP(ipStr)
	if ip == nil {
		return false
	}
	privateRanges := []string{
		"10.0.0.0/8",
		"172.16.0.0/12",
		"192.168.0.0/16",
		"127.0.0.0/8",
		"::1/128",
		"fc00::/7",
	}
	for _, cidr := range privateRanges {
		_, network, err := net.ParseCIDR(cidr)
		if err != nil {
			continue
		}
		if network.Contains(ip) {
			return true
		}
	}
	return false
}
