package core

import (
	"context"
	"crypto/aes"
	"crypto/cipher"
	"encoding/base32"
	"encoding/base64"
	"encoding/json"
	"fmt"
	g "proxy-server/gateway/globals"
	"time"
)

type SecuredReq struct {
	Content   string `json:"content"`
	Nonce     string `json:"nonce"`
	Timestamp int64  `json:"timestamp"`
}

func Decrypt[T any](req *SecuredReq, secretStr string) (resp *T, err error) {
	var encoding = base32.StdEncoding.WithPadding(base32.NoPadding)

	secret, err := encoding.DecodeString(secretStr)
	if err != nil {
		return nil, fmt.Errorf("解码密钥失败: %w", err)
	}

	// 解密请求
	block, err := aes.NewCipher(secret)
	if err != nil {
		return nil, err
	}

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	nonce, err := encoding.DecodeString(req.Nonce)
	if err != nil {
		return nil, err
	}

	content, err := base64.StdEncoding.DecodeString(req.Content)
	if err != nil {
		return nil, err
	}

	var aad = []byte(fmt.Sprintf("%s:%d", req.Nonce, req.Timestamp))

	bytes, err := gcm.Open(nil, nonce, content, aad)
	if err != nil {
		return nil, err
	}

	// 检查时间与 nonce 是否匹配
	var duration = time.Now().UnixMilli() - req.Timestamp
	if duration > 1000*60*5 { // 5分钟
		return nil, fmt.Errorf("请求超时，当前时间：%d，接收时间：%d", time.Now().UnixMilli(), req.Timestamp)
	}

	result, err := g.Redis.Exists(context.Background(), req.Nonce).Result()
	if err != nil {
		return nil, err
	}
	if result > 0 {
		return nil, fmt.Errorf("请求已被使用，nonce：%s", req.Nonce)
	}

	// 将 nonce 存入 redis，设置过期时间为 5 分钟
	err = g.Redis.Set(context.Background(), req.Nonce, 1, time.Minute*5).Err()
	if err != nil {
		return nil, err
	}

	// 返回解密后的数据
	err = json.Unmarshal(bytes, &resp)
	if err != nil {
		return nil, err
	}

	return resp, nil
}
