// Copyright (C) 2024 veypi <i@veypi.com>
// 2025-03-04 16:08:06
// Distributed under terms of the MIT license.

package auth

import (
	"strings"

	"github.com/veypi/vbase/cfg"
	"github.com/veypi/vbase/libs/cache"
	"github.com/veypi/vbase/libs/jwt"
	"github.com/veypi/vbase/models"
	"github.com/veypi/vigo"
)

// AuthMiddleware 统一认证中间件
// 1. JWT认证: 解析token，验证有效性，设置用户信息
// 2. 组织上下文: 如果请求包含org_id，验证用户成员身份，设置组织信息
func AuthMiddleware() func(*vigo.X) error {
	return func(x *vigo.X) error {
		// === 1. JWT 认证部分 ===
		tokenString := extractToken(x)
		if tokenString == "" {
			return vigo.ErrNotAuthorized.WithString("missing token")
		}

		// 解析token
		claims, err := jwt.ParseToken(tokenString)
		if err != nil {
			if err == jwt.ErrExpiredToken {
				return vigo.ErrNotAuthorized.WithString("token expired")
			}
			return vigo.ErrNotAuthorized.WithString("invalid token")
		}

		// 检查token是否在黑名单中
		if cache.IsEnabled() {
			blacklisted, _ := cache.IsTokenBlacklisted(claims.ID)
			if blacklisted {
				return vigo.ErrNotAuthorized.WithString("token has been revoked")
			}
		}

		// 将用户信息存入上下文
		x.Set("user_id", claims.UserID)
		x.Set("user_name", claims.Username)
		x.Set("user_orgs", claims.Orgs)
		x.Set("token_claims", claims)

		// === 2. 组织上下文部分 ===
		orgID := x.Request.Header.Get("X-Org-ID")
		if orgID == "" {
			orgID = x.Request.URL.Query().Get("org_id")
		}

		if orgID == "" {
			// 没有指定组织，仅完成用户认证
			return nil
		}

		// 验证用户是否为组织成员
		var member models.OrgMember
		if err := cfg.DB().Where("org_id = ? AND user_id = ? AND status = ?",
			orgID, claims.UserID, models.MemberStatusActive).First(&member).Error; err != nil {
			return vigo.ErrForbidden.WithString("you are not a member of this organization")
		}

		x.Set("org_id", orgID)
		x.Set("org_roles", member.RoleIDs)

		return nil
	}
}

func extractToken(x *vigo.X) string {
	auth := x.Request.Header.Get("Authorization")
	if auth != "" {
		if len(auth) > 7 && strings.HasPrefix(auth, "Bearer ") {
			return auth[7:]
		}
	}
	return x.Request.URL.Query().Get("access_token")
}
