package middleware

import (
	"net/http"
	"strings"

	"github.com/edu-cloud/api-gateway/internal/config"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
)

// publicPaths 是无需鉴权的公开路径（精确匹配，基于去掉 /api/v1 前缀后的路径）
var publicPaths = map[string]bool{
	"/iam/register": true,
	"/iam/login":    true,
	"/iam/refresh":  true,
}

// isPublicPath 判断请求路径是否属于公开路径（无需鉴权）
// 匹配规则：去掉 /api/v1 前缀后，与 publicPaths 精确匹配
func isPublicPath(path string) bool {
	stripped := strings.TrimPrefix(path, "/api/v1")
	return publicPaths[stripped]
}

// AuthMiddleware 验证 JWT 并注入用户信息到请求头
// P1 用 HS256，P2 改 RS256（IAM 签发）
func AuthMiddleware(cfg *config.Config) gin.HandlerFunc {
	return func(c *gin.Context) {
		// 健康检查跳过鉴权
		if c.Request.URL.Path == "/healthz" {
			c.Next()
			return
		}

		// 公开路径白名单（register/login/refresh 无需鉴权）
		if isPublicPath(c.Request.URL.Path) {
			c.Next()
			return
		}

		authHeader := c.GetHeader("Authorization")
		if authHeader == "" {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
				"success": false,
				"error": gin.H{
					"code":    "UNAUTHORIZED",
					"message": "missing authorization header",
				},
			})
			return
		}

		tokenStr := strings.TrimPrefix(authHeader, "Bearer ")
		if tokenStr == authHeader {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
				"success": false,
				"error": gin.H{
					"code":    "UNAUTHORIZED",
					"message": "invalid authorization scheme, expected Bearer",
				},
			})
			return
		}

		// 开发模式旁路：DEV_MODE=true 时接受 "dev-token"，注入开发用户
		// 仅用于本地联调，生产环境必须关闭 DEV_MODE
		if cfg.DevMode && tokenStr == "dev-token" {
			c.Request.Header.Set("x-user-id", "dev-user")
			c.Request.Header.Set("x-user-roles", "teacher,admin")
			c.Next()
			return
		}

		token, err := jwt.Parse(tokenStr, func(t *jwt.Token) (any, error) {
			if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
				return nil, jwt.ErrSignatureInvalid
			}
			return []byte(cfg.JWTSecret), nil
		})

		if err != nil || !token.Valid {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
				"success": false,
				"error": gin.H{
					"code":    "INVALID_TOKEN",
					"message": "token validation failed",
				},
			})
			return
		}

		claims, ok := token.Claims.(jwt.MapClaims)
		if !ok {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
				"success": false,
				"error": gin.H{
					"code":    "INVALID_CLAIMS",
					"message": "invalid token claims",
				},
			})
			return
		}

		// 注入用户信息到下游请求头
		if sub, ok := claims["sub"].(string); ok {
			c.Request.Header.Set("x-user-id", sub)
		}
		if roles, ok := claims["roles"].([]any); ok {
			roleStrs := make([]string, 0, len(roles))
			for _, r := range roles {
				if s, ok := r.(string); ok {
					roleStrs = append(roleStrs, s)
				}
			}
			c.Request.Header.Set("x-user-roles", strings.Join(roleStrs, ","))
		}

		c.Next()
	}
}
