package handlers

import (
	"context"
	"errors"
	"net/http"
	"time"

	"go.mongodb.org/mongo-driver/v2/bson"
	"go.mongodb.org/mongo-driver/v2/mongo"

	"yh_web/server/config"
	"yh_web/server/models"
	"yh_web/server/pkg/logger"
	"yh_web/server/utils"

	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
)

const jwtSecret = "yh_web_admin_jwt_secret_change_in_production"
const jwtExpire = 24 * time.Hour

type LoginInput struct {
	Username string `json:"username" binding:"required"`
	Password string `json:"password" binding:"required"`
}

type Claims struct {
	UserID   string `json:"user_id"`
	Username string `json:"username"`
	RoleID   int    `json:"role_id"`
	Role     string `json:"role"`
	jwt.RegisteredClaims
}

// Login 后台登录，仅 role_id=9527 超级管理员可登录
func Login(c *gin.Context) {
	var input LoginInput
	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "用户名和密码不能为空"})
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	coll := config.GetDB(config.DBName).Collection("users")
	var user models.User
	err := coll.FindOne(ctx, bson.M{"username": input.Username}).Decode(&user)
	if err != nil {
		if errors.Is(err, mongo.ErrNoDocuments) {
			// 尝试用手机号登录
			err = coll.FindOne(ctx, bson.M{"mobile": input.Username}).Decode(&user)
		}
		if err != nil {
			if errors.Is(err, mongo.ErrNoDocuments) {
				c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"})
				return
			}
			logger.Err("handlers/auth", "[Login] FindOne error: %v", err)
			resp := gin.H{"error": "登录失败，请稍后重试"}
			if gin.Mode() == gin.DebugMode {
				resp["debug"] = err.Error()
			}
			c.JSON(http.StatusInternalServerError, resp)
			return
		}
	}

	// 超级管理员(9527)或超级用户(role_id=0, role=admin)可登录后台
	if user.RoleID != models.RoleIDSuperAdmin && !(user.RoleID == models.RoleIDSuperUser && user.Role == "admin") {
		c.JSON(http.StatusForbidden, gin.H{"error": "无后台访问权限"})
		return
	}

	roleID := user.RoleID
	if roleID == 0 && user.Role == "admin" {
		roleID = models.RoleIDSuperAdmin
	}

	hashed := utils.HashPassword(input.Password)
	if hashed != user.Password {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"})
		return
	}

	claims := Claims{
		UserID:   user.ID.Hex(),
		Username: user.Username,
		RoleID:   roleID,
		Role:     user.Role,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(jwtExpire)),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	tokenStr, err := token.SignedString([]byte(jwtSecret))
	if err != nil {
		logger.Err("handlers/auth", "JWT SignedString error: %v", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "生成令牌失败"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"token": tokenStr,
		"user": gin.H{
			"id":       user.ID.Hex(),
			"username": user.Username,
			"role_id":  roleID,
			"role":     user.Role,
		},
		"expires_in": int64(jwtExpire.Seconds()),
	})
}

// AuthRequired 鉴权中间件，要求 role_id=9527
func AuthRequired() gin.HandlerFunc {
	return func(c *gin.Context) {
		tokenStr := c.GetHeader("Authorization")
		if tokenStr == "" {
			tokenStr = c.Query("token")
		}
		if len(tokenStr) > 7 && tokenStr[:7] == "Bearer " {
			tokenStr = tokenStr[7:]
		}
		if tokenStr == "" {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"})
			c.Abort()
			return
		}

		var claims Claims
		token, err := jwt.ParseWithClaims(tokenStr, &claims, func(t *jwt.Token) (interface{}, error) {
			return []byte(jwtSecret), nil
		})
		if err != nil || !token.Valid {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "登录已过期，请重新登录"})
			c.Abort()
			return
		}

		// 仅超级管理员或超级用户(role_id=0, role=admin)可访问后台
		if claims.RoleID != models.RoleIDSuperAdmin && !(claims.RoleID == models.RoleIDSuperUser && claims.Role == "admin") {
			c.JSON(http.StatusForbidden, gin.H{"error": "无后台访问权限"})
			c.Abort()
			return
		}

		c.Set("user_id", claims.UserID)
		c.Set("username", claims.Username)
		c.Set("role_id", claims.RoleID)
		c.Set("role", claims.Role)
		c.Next()
	}
}

// SuperUserAuthRequired 超级用户鉴权：仅 role_id=0 且 role=admin 可访问（如短信平台配置）
// 集团超级用户 username=admin 只能配置集团信息，不能配置短信
func SuperUserAuthRequired() gin.HandlerFunc {
	return func(c *gin.Context) {
		tokenStr := c.GetHeader("Authorization")
		if tokenStr == "" {
			tokenStr = c.Query("token")
		}
		if len(tokenStr) > 7 && tokenStr[:7] == "Bearer " {
			tokenStr = tokenStr[7:]
		}
		if tokenStr == "" {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "请先登录"})
			c.Abort()
			return
		}

		var claims Claims
		token, err := jwt.ParseWithClaims(tokenStr, &claims, func(t *jwt.Token) (interface{}, error) {
			return []byte(jwtSecret), nil
		})
		if err != nil || !token.Valid {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "登录已过期，请重新登录"})
			c.Abort()
			return
		}

		// 仅 role_id=9527 且 role=admin 可配置短信平台
		if claims.RoleID != models.RoleIDSuperAdmin || claims.Role != "admin" {
			c.JSON(http.StatusForbidden, gin.H{"error": "仅超级管理员可配置短信平台"})
			c.Abort()
			return
		}

		c.Set("user_id", claims.UserID)
		c.Set("username", claims.Username)
		c.Set("role_id", claims.RoleID)
		c.Set("role", claims.Role)
		c.Next()
	}
}
