package main

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
	"golang.org/x/crypto/bcrypt"
)

var jwtSecretCache []byte

func getJwtSecret() []byte {
	if len(jwtSecretCache) > 0 {
		return jwtSecretCache
	}
	secret, err := GetJwtSecret()
	if err != nil {
		log.Fatal("❌ 获取 JWT 密钥失败:", err)
	}
	jwtSecretCache = []byte(secret)
	return jwtSecretCache
}

type Claims struct {
	Username string `json:"username"`
	jwt.RegisteredClaims
}

func GenerateJWT(username string) (string, error) {
	claims := Claims{
		Username: username,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(7 * 24 * time.Hour)),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(getJwtSecret())
}

func ParseJWT(tokenString string) (*Claims, error) {
	token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		return getJwtSecret(), nil
	})
	if err != nil {
		return nil, err
	}
	if claims, ok := token.Claims.(*Claims); ok && token.Valid {
		return claims, nil
	}
	return nil, errors.New("invalid token")
}

func ValidatePassword(pwd string) bool {
	if len(pwd) < 8 {
		return false
	}
	var hasUpper, hasLower, hasDigit, hasSpecial bool
	for _, ch := range pwd {
		if ch >= 'A' && ch <= 'Z' {
			hasUpper = true
		} else if ch >= 'a' && ch <= 'z' {
			hasLower = true
		} else if ch >= '0' && ch <= '9' {
			hasDigit = true
		} else if strings.ContainsAny(string(ch), "!@#$%^&*()_+-=[]{}|;:,.<>?") {
			hasSpecial = true
		}
	}
	return hasUpper && hasLower && hasDigit && hasSpecial
}

func InitAdminUser() {
	count, err := CountUsers()
	if err != nil {
		log.Fatal("❌ 检查用户表失败:", err)
	}
	if count > 0 {
		log.Println("✅ 已存在管理员账户，跳过初始化")
		return
	}
	log.Println("⚠️  首次启动，请设置管理员账户")
	log.Print("用户名: ")
	var username string
	fmt.Scanln(&username)
	if username == "" {
		username = "admin"
	}
	for {
		log.Print("密码 (至少8位，含大小写、数字、特殊字符): ")
		var password string
		fmt.Scanln(&password)
		if ValidatePassword(password) {
			hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
			if err != nil {
				log.Println("❌ 密码加密失败:", err)
				continue
			}
			err = CreateUser(username, string(hash))
			if err != nil {
				log.Println("❌ 创建用户失败:", err)
				continue
			}
			log.Println("✅ 管理员账户创建成功！")
			break
		} else {
			log.Println("❌ 密码不符合复杂度要求，请重新输入")
			log.Println("   要求: 至少8位，包含大小写字母、数字和特殊字符")
		}
	}
}

func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		authHeader := c.GetHeader("Authorization")
		if authHeader == "" {
			c.JSON(http.StatusUnauthorized, gin.H{"code": 1, "msg": "未提供认证令牌"})
			c.Abort()
			return
		}
		parts := strings.SplitN(authHeader, " ", 2)
		if len(parts) != 2 || parts[0] != "Bearer" {
			c.JSON(http.StatusUnauthorized, gin.H{"code": 1, "msg": "认证令牌格式错误"})
			c.Abort()
			return
		}
		claims, err := ParseJWT(parts[1])
		if err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{"code": 1, "msg": "无效的认证令牌"})
			c.Abort()
			return
		}
		c.Set("username", claims.Username)
		c.Next()
	}
}
