package middleware

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

	"github.com/gin-gonic/gin"
	"git.iioio.com/freefire/jiang13-forum/model"
	"git.iioio.com/freefire/jiang13-forum/service"
)

const (
	CtxUserID   = "user_id"
	CtxUsername = "username"
	CtxRole     = "role"
	CookieName  = "jiang13_token"
)

type AuthMiddleware struct {
	auth *service.AuthService
}

func NewAuthMiddleware(auth *service.AuthService) *AuthMiddleware {
	return &AuthMiddleware{auth: auth}
}

// OptionalAuth 可选鉴权：有 token 则解析，无 token 不拦截。
// 用户已删除或不存在时清除失效 cookie，避免前端误显示为已登录。
func (m *AuthMiddleware) OptionalAuth() gin.HandlerFunc {
	return func(c *gin.Context) {
		token := extractToken(c)
		if token != "" {
			if claims, err := m.auth.ParseToken(token); err == nil {
				var user model.User
				if err := model.DB.Select("id", "username", "role").First(&user, claims.UserID).Error; err != nil {
					c.SetCookie(CookieName, "", -1, "/", "", false, true)
				} else {
					c.Set(CtxUserID, user.ID)
					c.Set(CtxUsername, user.Username)
					c.Set(CtxRole, user.Role)
					m.auth.TouchLastAccess(user.ID)
				}
			}
		}
		c.Next()
	}
}

// RequireAuth 必须登录
func (m *AuthMiddleware) RequireAuth() gin.HandlerFunc {
	return func(c *gin.Context) {
		token := extractToken(c)
		if token == "" {
			respondAuthRequired(c)
			c.Abort()
			return
		}
		claims, err := m.auth.ParseToken(token)
		if err != nil {
			respondAuthExpired(c)
			c.Abort()
			return
		}
		// 检查禁言
		var user model.User
		if err := model.DB.First(&user, claims.UserID).Error; err != nil || user.Banned {
			respondBanned(c)
			c.Abort()
			return
		}
		c.Set(CtxUserID, claims.UserID)
		c.Set(CtxUsername, claims.Username)
		c.Set(CtxRole, claims.Role)
		m.auth.TouchLastAccess(claims.UserID)
		c.Next()
	}
}

// RequireAdmin 必须管理员
func (m *AuthMiddleware) RequireAdmin() gin.HandlerFunc {
	return func(c *gin.Context) {
		role, exists := c.Get(CtxRole)
		if !exists || role != model.RoleAdmin {
			if isAPI(c) {
				c.JSON(http.StatusForbidden, gin.H{"error": "需要管理员权限"})
			} else {
				c.Redirect(http.StatusFound, "/admin/login")
			}
			c.Abort()
			return
		}
		c.Next()
	}
}

func extractToken(c *gin.Context) string {
	if auth := c.GetHeader("Authorization"); auth != "" {
		if strings.HasPrefix(auth, "Bearer ") {
			return strings.TrimPrefix(auth, "Bearer ")
		}
	}
	if token, err := c.Cookie(CookieName); err == nil {
		return token
	}
	return ""
}

func isAPI(c *gin.Context) bool {
	return strings.HasPrefix(c.Request.URL.Path, "/api/")
}

func adminLoginPath(c *gin.Context) string {
	if strings.HasPrefix(c.Request.URL.Path, "/admin") {
		return "/admin/login"
	}
	return "/login"
}

func respondAuthRequired(c *gin.Context) {
	if isAPI(c) {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"})
		return
	}
	c.Redirect(http.StatusFound, adminLoginPath(c))
}

func respondAuthExpired(c *gin.Context) {
	c.SetCookie(CookieName, "", -1, "/", "", false, true)
	if isAPI(c) {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "登录已过期"})
		return
	}
	c.Redirect(http.StatusFound, adminLoginPath(c))
}

func respondBanned(c *gin.Context) {
	if isAPI(c) {
		c.JSON(http.StatusForbidden, gin.H{"error": "账号已被禁言"})
		return
	}
	if strings.HasPrefix(c.Request.URL.Path, "/admin") {
		c.Redirect(http.StatusFound, "/admin/login?banned=1")
		return
	}
	c.Redirect(http.StatusFound, "/login?banned=1")
}

// RateLimitMiddleware 限流中间件
func RateLimitMiddleware(limiter *service.RateLimiter, action string) gin.HandlerFunc {
	return func(c *gin.Context) {
		key := c.ClientIP()
		if uid, ok := c.Get(CtxUserID); ok {
			key = fmt.Sprintf("%d", uid.(uint))
		}
		if !limiter.Allow(action, key) {
			c.JSON(http.StatusTooManyRequests, gin.H{"error": "操作过于频繁，请稍后再试"})
			c.Abort()
			return
		}
		c.Next()
	}
}
