package api

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

	"github.com/gin-gonic/gin"

	"oci-portal/internal/service"
)

// ctxRealIPKey 是真实IP中间件写入 gin.Context 的键。
const ctxRealIPKey = "realIP"

// RealIPMiddleware 按安全设置解析客户端真实 IP 写入上下文,
// 全链路(IP 限速 / 登录守卫 / 系统日志留痕)统一消费;gin 内置
// TrustedProxies 已禁用,信任边界完全由该配置决定。
func RealIPMiddleware(settings *service.SettingService) gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Set(ctxRealIPKey, resolveRealIP(c.Request, settings.SecurityCached().RealIPHeader))
		c.Next()
	}
}

// requestIP 取中间件解析的真实 IP;未经中间件(单测直调 handler)时回退 RemoteAddr。
func requestIP(c *gin.Context) string {
	if ip := c.GetString(ctxRealIPKey); ip != "" {
		return ip
	}
	return remoteHost(c.Request)
}

// resolveRealIP 依配置头解析:X-Forwarded-For 取链尾(直连反代的对端,
// 反代会把对端追加到链尾,链首可被客户端伪造);X-Real-IP 等单值头直取;
// 头缺失或未配置(直连部署)回退 RemoteAddr。
func resolveRealIP(r *http.Request, header string) string {
	switch header {
	case "":
	case "X-Forwarded-For":
		if v := r.Header.Get(header); v != "" {
			parts := strings.Split(v, ",")
			if ip := strings.TrimSpace(parts[len(parts)-1]); ip != "" {
				return ip
			}
		}
	default:
		if ip := strings.TrimSpace(r.Header.Get(header)); ip != "" {
			return ip
		}
	}
	return remoteHost(r)
}

// remoteHost 取 RemoteAddr 的 host 部分。
func remoteHost(r *http.Request) string {
	host, _, err := net.SplitHostPort(r.RemoteAddr)
	if err != nil {
		return r.RemoteAddr
	}
	return host
}
