package middleware

import (
	"errors"
	"strconv"

	"git.echol.cn/loser/st/server/global"
	"git.echol.cn/loser/st/server/model/app"
	"git.echol.cn/loser/st/server/model/common/response"
	"git.echol.cn/loser/st/server/utils"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
)

// AppJWTAuth 前台用户 JWT 认证中间件
func AppJWTAuth() gin.HandlerFunc {
	return func(c *gin.Context) {
		token := GetToken(c)
		if token == "" {
			response.FailWithDetailed(gin.H{"reload": true}, "未登录或非法访问", c)
			c.Abort()
			return
		}

		// 解析 JWT
		claims, err := utils.ParseAppToken(token)
		if err != nil {
			if errors.Is(err, jwt.ErrTokenExpired) {
				response.FailWithDetailed(gin.H{"reload": true}, "Token 已过期", c)
			} else {
				response.FailWithDetailed(gin.H{"reload": true}, "Token 无效", c)
			}
			c.Abort()
			return
		}

		// 验证用户类型（确保是前台用户）
		if claims.UserType != utils.UserTypeApp {
			response.FailWithMessage("无效的用户类型", c)
			c.Abort()
			return
		}

		// 查询用户是否存在
		var user app.AppUser
		err = global.GVA_DB.Where("id = ?", claims.UserID).First(&user).Error
		if err != nil {
			response.FailWithMessage("用户不存在", c)
			c.Abort()
			return
		}

		// 检查用户状态
		if !user.Enable {
			response.FailWithMessage("用户已被禁用", c)
			c.Abort()
			return
		}

		if user.Status != "active" {
			response.FailWithMessage("账户状态异常", c)
			c.Abort()
			return
		}

		// 将用户信息存入上下文
		c.Set("appUserId", user.ID)
		c.Set("appUser", &user)
		c.Set("appUsername", user.Username)

		c.Next()
	}
}

// GetAppUserID 从上下文获取前台用户 ID（需要鉴权的接口使用）
func GetAppUserID(c *gin.Context) uint {
	if userID, exists := c.Get("appUserId"); exists {
		return userID.(uint)
	}
	return 0
}

// GetOptionalAppUserID 从上下文获取可选的前台用户 ID（公开接口使用）
// 如果用户已登录，返回用户 ID；否则返回 nil
func GetOptionalAppUserID(c *gin.Context) *uint {
	// 先尝试从上下文获取（通过鉴权中间件设置）
	if userID, exists := c.Get("appUserId"); exists {
		if id, ok := userID.(uint); ok {
			return &id
		}
	}

	// 如果上下文中没有，尝试手动解析 Token（用于公开接口）
	token := GetToken(c)
	if token == "" {
		return nil
	}

	claims, err := utils.ParseAppToken(token)
	if err != nil {
		return nil
	}

	if claims.UserType != utils.UserTypeApp {
		return nil
	}

	return &claims.UserID
}

// GetAppUser 从上下文获取前台用户信息
func GetAppUser(c *gin.Context) *app.AppUser {
	if user, exists := c.Get("appUser"); exists {
		return user.(*app.AppUser)
	}
	return nil
}

// GetAppUsername 从上下文获取前台用户名
func GetAppUsername(c *gin.Context) string {
	if username, exists := c.Get("appUsername"); exists {
		return username.(string)
	}
	return ""
}

// GetToken 从请求中获取 Token
// 优先从 Header 获取，其次从 Query 参数获取
func GetToken(c *gin.Context) string {
	token := c.Request.Header.Get("x-token")
	if token == "" {
		token = c.Request.Header.Get("Authorization")
		if token != "" && len(token) > 7 && token[:7] == "Bearer " {
			token = token[7:]
		}
	}
	if token == "" {
		token = c.Query("token")
	}
	return token
}

// SetAppUserID 设置用户 ID 到上下文（用于某些特殊场景）
func SetAppUserID(c *gin.Context, userID uint) {
	c.Set("appUserId", userID)
	c.Set("appUserIdStr", strconv.Itoa(int(userID)))
}
