package middleware

import (
	"net/http"
	"os"
	"strconv"
	"strings"

	"github.com/gin-gonic/gin"

	"github.com/sundynix/sundynix-gateway/internal/auth"
)

// CtxUserID 是鉴权后写入 gin.Context 的已验证用户 ID 键。
const CtxUserID = "uid"

// Auth 解析 Authorization: Bearer <JWT>，校验通过则把已验证 userID 写入上下文。
// 非阻断：无 token / 无效 token 时不报错，由各 handler（经 userID 兜底 header）或
// 后续 RequireAuth 决定是否放行。
func Auth() gin.HandlerFunc {
	return func(c *gin.Context) {
		h := c.GetHeader("Authorization")
		if strings.HasPrefix(h, "Bearer ") {
			if uid, err := auth.Parse(strings.TrimSpace(h[len("Bearer "):])); err == nil {
				c.Set(CtxUserID, uid)
			}
		}
		c.Next()
	}
}

// RequireAuth 在 Auth 之后使用：上下文无已验证 userID 则 401 拒绝。
// 用于 owner 作用域的业务路由；SSE/导出等按 task_id 寻址的端点不挂（EventSource 无法带头）。
func RequireAuth() gin.HandlerFunc {
	return func(c *gin.Context) {
		if v, ok := c.Get(CtxUserID); ok {
			if s, _ := v.(string); s != "" {
				c.Next()
				return
			}
		}
		c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "需要登录"})
	}
}

// RequireAdmin 保护运维控制面：必须登录，且（设了 ADMIN_USER_IDS 时）uid 须在白名单内。
// ADMIN_USER_IDS 为空：开发期放行任意登录用户；生产期(APP_ENV=prod/GIN_MODE=release)直接拒绝
// ——逼运维显式配置管理员，杜绝"任意账号改模型/密钥配置"。
func RequireAdmin() gin.HandlerFunc {
	allow := splitEnv("ADMIN_USER_IDS")
	prod := strings.EqualFold(os.Getenv("APP_ENV"), "production") || strings.EqualFold(os.Getenv("APP_ENV"), "prod") ||
		strings.EqualFold(os.Getenv("GIN_MODE"), "release")
	return func(c *gin.Context) {
		uid, _ := c.Get(CtxUserID)
		id, _ := uid.(string)
		if id == "" {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "需要登录"})
			return
		}
		if len(allow) == 0 {
			if prod {
				c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "未配置管理员（ADMIN_USER_IDS）"})
				return
			}
			c.Next() // 开发期放行
			return
		}
		for _, a := range allow {
			if a == id {
				c.Next()
				return
			}
		}
		c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "需要管理员权限"})
	}
}

func splitEnv(key string) []string {
	var out []string
	for _, p := range strings.Split(os.Getenv(key), ",") {
		if p = strings.TrimSpace(p); p != "" {
			out = append(out, p)
		}
	}
	return out
}

// envInt 读正整数环境变量，缺省回退 def。
func envInt(key string, def int) int {
	if v := os.Getenv(key); v != "" {
		if n, err := strconv.Atoi(v); err == nil && n > 0 {
			return n
		}
	}
	return def
}
