package util

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"errors"
	"fmt"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gctx"
	"github.com/gogf/gf/v2/util/gconv"
	"io"
	"log"
	"os"
	"time"
)

var (
	PublicKey  *rsa.PublicKey
	PrivateKey *rsa.PrivateKey
)

func InitApiEncryptPrivatePublicKey() {
	// 读取私钥文件
	privateKeyBytes, err := os.ReadFile("./etc/rsa/apiEncrypt_private_key.pem")
	if err != nil {
		log.Println("无法读取私钥文件：", err)
		return
	}
	// 解码私钥
	privateKeyBlock, _ := pem.Decode(privateKeyBytes)
	if privateKeyBlock == nil || privateKeyBlock.Type != "PRIVATE KEY" {
		log.Println("私钥文件格式错误")
		return
	}

	// 解析私钥
	privateKeys, err := x509.ParsePKCS8PrivateKey(privateKeyBlock.Bytes)
	if err != nil {
		log.Println("私钥解析失败：", err)
		return
	}

	// 转换为RSA类型的私钥
	rsaPrivateKey, ok := privateKeys.(*rsa.PrivateKey)
	if !ok {
		fmt.Println("无法转换为RSA类型的私钥")
		return
	}
	PrivateKey = rsaPrivateKey
	// 读取公钥文件
	publicKeyBytes, err := os.ReadFile("./etc/rsa/apiEncrypt_public_key.pem")
	if err != nil {
		log.Println("无法读取公钥文件：", err)
		return
	}
	log.Println("读取公钥文件")
	// 解码公钥
	publicKeyBlock, _ := pem.Decode(publicKeyBytes)
	if publicKeyBlock == nil || publicKeyBlock.Type != "PUBLIC KEY" {
		log.Println("公钥文件格式错误", publicKeyBlock.Type)
		return
	}

	// 解析公钥
	publicKeyInterface, err := x509.ParsePKIXPublicKey(publicKeyBlock.Bytes)
	if err != nil {
		log.Println("公钥解析失败：", err.Error())
		return
	}

	// 转换为公钥类型
	rsaPublicKey, ok := publicKeyInterface.(*rsa.PublicKey)
	if !ok {
		log.Println("无法转换为公钥类型")
		return
	}
	PublicKey = rsaPublicKey
	log.Println("初始化公钥成功", PublicKey)
}

// JyAntiEncrypt 接口数据加密
func JyAntiEncrypt(plaintext []byte) (out, PKeyStr string, err error) {
	if plaintext == nil {
		return
	}
	if PublicKey == nil {
		err = errors.New("无效公钥")
		return
	}

	var aseByte = func() (rBytes []byte) {
		aesEncDecKey := g.Cfg().MustGet(gctx.New(), "apiEncryptKey", "JyEncrypt").String()
		if len(aesEncDecKey) >= aes.BlockSize {
			return gconv.Bytes(aesEncDecKey[:aes.BlockSize])
		}
		return gconv.Bytes(fmt.Sprintf("%s%s", aesEncDecKey, time.Now().Format("20060102150405"))[:aes.BlockSize])
	}()

	if len(aseByte) == 0 {
		return
	}

	out, err = SymmetricEncrypt(plaintext, aseByte)
	if err != nil {
		return
	}
	//非对称加密
	var pKeyByte []byte
	pKeyByte, err = rsa.EncryptPKCS1v15(rand.Reader, PublicKey, aseByte)
	if err == nil {
		PKeyStr = base64.StdEncoding.EncodeToString(pKeyByte)
	}
	return
}

// SymmetricEncrypt 对称加密
func SymmetricEncrypt(plaintext []byte, key []byte) (string, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return "", err
	}

	ciphertext := make([]byte, aes.BlockSize+len(plaintext))

	iv := ciphertext[:aes.BlockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		return "", err
	}

	stream := cipher.NewCTR(block, iv)
	stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)

	return base64.StdEncoding.EncodeToString(ciphertext), nil
}
