package utils

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"encoding/hex"
	"exhibitionCentre/config"
	"exhibitionCentre/logging"
	"io"
	"io/ioutil"
	"time"

	"github.com/dgrijalva/jwt-go"
)

type JWTCustomClaims struct {
	UserId uint   `json:"user_id"`
	Email  string `json:"email"`
	Role   int    `json:"role"`
	jwt.StandardClaims
}

const JWT_EXPIRATION_TIME = 1000000000 * 60 * 60 * 24 * 7 // 7days

var table = [...]byte{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'}

func GenerateVerificationCode(codeLen int) string {
	b := make([]byte, codeLen)
	n, err := io.ReadAtLeast(rand.Reader, b, codeLen)
	if n != codeLen {
		panic(err)
	}
	for i := 0; i < len(b); i++ {
		b[i] = table[int(b[i])%len(table)]
	}
	return string(b)
}

func GenerateSecret(secret string) (string, error) {
	pwdKeyPath := config.Config.Certificate.PasswordPrivateKey
	key, _ := ioutil.ReadFile(pwdKeyPath)
	var rsaPSSKey *rsa.PrivateKey
	var err error
	if rsaPSSKey, err = jwt.ParseRSAPrivateKeyFromPEM(key); err != nil {
		logging.Log.Errorf("Unable to parse RSA private key: %v", err)
		return "", err
	}
	sha_pwd := SHA(secret)
	sha_pri := SHA(rsaPSSKey.D.String())
	return SHA(sha_pwd + sha_pri), nil
}

func SHA(str string) string {
	// Converts string to sha2
	h := sha256.New()
	h.Write([]byte(str))
	code := h.Sum(nil)
	codestr := hex.EncodeToString(code)

	return codestr
}

func DecodePwd(str string) {
	//var dest []byte
	dest, _ := hex.DecodeString(str)
	logging.Log.Error(string(dest))
}

func GenerateJWT(userId uint, email string, role int) (string, error) {
	signingKey, err := ReadJWTPrivateKey()
	if err != nil {
		return "", err
	}

	issuer := config.Config.App.Issuer

	// Create the Claims
	claims := JWTCustomClaims{
		userId,
		email,
		role,
		jwt.StandardClaims{
			ExpiresAt: time.Now().Add(JWT_EXPIRATION_TIME).Unix(),
			Issuer:    issuer,
		},
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(signingKey)
}

func ParseJWT(jwtString string) *JWTCustomClaims {
	//eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdXJpc2RpY3Rpb25MZXZlbCI6MSwiZXhwIjoxNTI4ODk1ODg0LCJpc3MiOiJIdW1ibGUifQ.5m8ojwawO3YMvuc5qua1QpSA-CLwU-j8FUQu446p8pI
	token, err := jwt.ParseWithClaims(jwtString, &JWTCustomClaims{}, func(token *jwt.Token) (interface{}, error) {
		signingKey, err := ReadJWTPrivateKey()
		if err != nil {
			return "", err
		}
		return signingKey, nil
	})
	if err != nil {
		return nil
	}

	claims, ok := token.Claims.(*JWTCustomClaims)
	if ok && token.Valid {
		return claims
	}
	return nil
}

func ReadJWTPrivateKey() ([]byte, error) {
	jwtKeyPath := config.Config.Certificate.JwtPrivatekey
	key, _ := ioutil.ReadFile(jwtKeyPath)
	var rsaPSSKey *rsa.PrivateKey
	var err error
	if rsaPSSKey, err = jwt.ParseRSAPrivateKeyFromPEM(key); err != nil {
		logging.Log.Errorf("Unable to parse RSA private key: %v", err)
		return nil, err
	}
	signingKey := []byte(rsaPSSKey.D.String())
	return signingKey, nil
}
