package utils

import (
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"errors"
	"fmt"
)

const (
	keyLengthByte     = 32 // AES-256 密钥长度（字节）
	authTagLengthByte = 16 // GCM 认证标签长度（字节）
)

// AesUtil 用于微信支付 AES-256-GCM 解密的工具类
type AesUtil struct {
	aesKey []byte // 32字节的AES密钥
}

// NewAesUtil 创建AesUtil实例，验证密钥长度
func NewAesUtil(aesKey string) (*AesUtil, error) {
	if len(aesKey) != keyLengthByte {
		return nil, errors.New("无效的ApiV3Key，长度应为32个字节")
	}
	return &AesUtil{aesKey: []byte(aesKey)}, nil
}

// DecryptToString 解密 AEAD_AES_256_GCM 加密的数据
// associatedData: 附加认证数据
// nonceStr: 随机数（12字节）
// ciphertext: 加密后的密文（Base64编码）
func (a *AesUtil) DecryptToString(associatedData, nonceStr, ciphertext string) (string, error) {
	// 1. Base64解码密文
	cipherBytes, err := base64.StdEncoding.DecodeString(ciphertext)
	if err != nil {
		return "", fmt.Errorf("密文Base64解码失败: %w", err)
	}

	// 2. 验证密文长度（需包含认证标签）
	if len(cipherBytes) <= authTagLengthByte {
		return "", errors.New("密文长度不足，无法解析认证标签")
	}

	// 3. 分离密文和认证标签（GCM模式中，认证标签通常附加在密文末尾）
	ctext := cipherBytes[:len(cipherBytes)-authTagLengthByte]
	authTag := cipherBytes[len(cipherBytes)-authTagLengthByte:]

	// 4. 初始化AES-GCM加密器
	block, err := aes.NewCipher(a.aesKey)
	if err != nil {
		return "", fmt.Errorf("创建AES加密器失败: %w", err)
	}

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return "", fmt.Errorf("创建GCM模式失败: %w", err)
	}

	// 5. 构建附加数据（GCM的AAD）
	additionalData := []byte(associatedData)

	// 6. 解密（GCM模式会自动验证认证标签）
	plaintext, err := gcm.Open(nil, []byte(nonceStr), append(ctext, authTag...), additionalData)
	if err != nil {
		return "", fmt.Errorf("解密失败（可能是密钥错误或数据被篡改）: %w", err)
	}

	return string(plaintext), nil
}

type Resource struct {
	OriginalType   string `json:"original_type"`
	Algorithm      string `json:"algorithm"`
	Ciphertext     string `json:"ciphertext"`      // 如支付通知中的 encrypted_data
	AssociatedData string `json:"associated_data"` // 微信支付回调的附加数据 通常为空字符串或回调相关信息
	Nonce          string `json:"nonce"`           // 12字节字符串
}

type WxNotifyBody struct {
	Id           string   `json:"id"`
	CreateTime   string   `json:"create_time"`
	ResourceType string   `json:"resource_type"`
	EventType    string   `json:"event_type"`
	Summary      string   `json:"summary"`
	Resource     Resource `json:"resource"`
}
