package token

import (
	"errors"
	"gadmin/config"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"github.com/sirupsen/logrus"
	"os"
	"time"
)

type UserClaims struct {
	ID          int64  `json:"user_id"`
	UserName    string `json:"user_name"`
	RoleId      int64  `json:"role_id"`
	Avatar      string `json:"avatar"`
	Nickname    string `json:"nickname"`
	SystemId    int32  `json:"system_id"`
	AccessToken string `json:"access_token"`
	jwt.StandardClaims
}

var (
	secret     = []byte(os.Getenv("JWT_SECRET"))
	effectTime = 30 * 24 * time.Hour // 30天有效期
)

func GenerateToken(claims *UserClaims) (token string, err error) {
	claims.ExpiresAt = time.Now().Add(effectTime).Unix()
	sign, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString(secret)
	if err != nil {
		return "", err
	}
	return sign, nil
}

func ParseToken(tokenString string) (claims *UserClaims, err error) {
	token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) {
		return secret, nil
	})
	if err != nil {
		return nil, err
	}
	claims, ok := token.Claims.(*UserClaims)
	if !ok {
		return nil, errors.New("token is valid")
	}
	return claims, nil
}

func Refresh(tokenString string) (t string, err error) {
	jwt.TimeFunc = func() time.Time {
		return time.Unix(0, 0)
	}
	token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) {
		return secret, nil
	})
	if err != nil {
		return "", err
	}
	claims, ok := token.Claims.(*UserClaims)
	if !ok {
		return "", errors.New("token is valid")
	}
	jwt.TimeFunc = time.Now
	claims.StandardClaims.ExpiresAt = time.Now().Add(effectTime).Unix()
	return GenerateToken(claims)
}

func Layout(tokenString string) (err error) {
	jwt.TimeFunc = func() time.Time {
		return time.Unix(0, 0)
	}
	_, err = jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) {
		return secret, nil
	})
	if err != nil {
		return err
	}
	return
}

func GetAuthorization(c *gin.Context) (t string) {
	t = c.GetHeader("authorization")
	if t == "" {
		t = c.Request.URL.Query().Get("authorization")
	}

	return t
}

func CurrentUser(c *gin.Context) *UserClaims {
	if user, _ := c.Get("user"); user != nil {
		if u, ok := user.(*UserClaims); ok {
			return u
		}
	}
	logrus.Warn("CurrentUser = nil")
	return nil
}

func GetUID(c *gin.Context) int64 {
	user := CurrentUser(c)
	if user == nil {
		return 0
	}
	return user.ID
}

func GetUserName(c *gin.Context) string {
	user := CurrentUser(c)
	if user == nil {
		return `游客`
	}
	return user.UserName
}

func GetSystemId(c *gin.Context) int32 {
	user := CurrentUser(c)
	if user == nil {
		return 0
	}
	return user.SystemId
}

func SetSystemId(c *gin.Context, systemId int32) (string, error) {
	t := GetAuthorization(c)
	user, err := ParseToken(t)
	if err != nil {
		return "", err
	}
	err = Layout(t)
	if err != nil {
		return "", err
	}
	user.SystemId = systemId

	jwt.TimeFunc = time.Now
	user.StandardClaims.ExpiresAt = time.Now().Add(effectTime).Unix()
	t, err = GenerateToken(user)
	if err != nil {
		return "", err
	}
	// 记录登录token
	key := config.GetUserTokenKey(user.ID)
	config.TokenRedis.HSet(key, t, time.Now().Unix())
	config.TokenRedis.Expire(key, config.TokenExpireTime)
	return t, nil
}

func GenerateTokenUsingUUID() string {
	return uuid.New().String()
}
