# utils/wechat_v3.py
'''import time
import hashlib
import base64
import json
from urllib.parse import urlparse

import rsa
from Crypto.Cipher import AES

from django.conf import settings


def load_private_key():
    """加载商户私钥（PEM格式）"""
    with open(settings.WECHAT_PAY_V3_CONFIG['PRIVATE_KEY_PATH'], 'rb') as f:
        key_data = f.read()
    return rsa.PrivateKey.load_pkcs1(key_data)


def build_authorization(method, url, body):
    """
    生成V3接口的Authorization头
    :param method: GET/POST
    :param url: 完整URL（含域名和路径）
    :param body: 请求体JSON字符串
    :return: Authorization字符串
    """
    private_key = load_private_key()
    mchid = settings.WECHAT_PAY_V3_CONFIG['MCHID']
    serial_no = settings.WECHAT_PAY_V3_CONFIG['CERT_SERIAL_NO']

    # 提取URL路径（不含query）
    parsed = urlparse(url)
    path = parsed.path
    if parsed.query:
        path += '?' + parsed.query

    timestamp = str(int(time.time()))
    nonce = hashlib.md5((timestamp + 'wechat').encode()).hexdigest()[:32]

    # 构造签名串
    message = '\n'.join([method, path, timestamp, nonce, body]) + '\n'

    # 使用私钥签名（SHA256）
    signature = rsa.sign(message.encode('utf-8'), private_key, 'SHA-256')
    signature_b64 = base64.b64encode(signature).decode('utf-8')

    # 组装Authorization
    auth = f'WECHATPAY2-SHA256-RSA2048 mchid="{mchid}",nonce_str="{nonce}",timestamp="{timestamp}",serial_no="{serial_no}",signature="{signature_b64}"'
    return auth


def verify_wechat_sign(headers, body):
    """
    验证微信回调的签名
    需要提前从微信平台下载证书公钥，存放在 PLATFORM_CERT_DIR 下，文件名 = 序列号.pem
    :param headers: 请求头
    :param body: 原始请求体字符串
    :return: bool
    """
    serial = headers.get('Wechatpay-Serial')
    signature = headers.get('Wechatpay-Signature')
    timestamp = headers.get('Wechatpay-Timestamp')
    nonce = headers.get('Wechatpay-Nonce')

    if not all([serial, signature, timestamp, nonce]):
        return False

    # 构造验签名串
    message = '\n'.join([timestamp, nonce, body]) + '\n'

    # 读取对应序列号的平台证书公钥
    cert_path = f"{settings.WECHAT_PAY_V3_CONFIG['PLATFORM_CERT_DIR']}/{serial}.pem"
    try:
        with open(cert_path, 'rb') as f:
            pub_key = rsa.PublicKey.load_pkcs1_openssl_pem(f.read())
    except FileNotFoundError:
        # 如果证书不存在，可尝试下载（生产环境建议定时下载）
        return False

    signature_bytes = base64.b64decode(signature)
    try:
        rsa.verify(message.encode('utf-8'), signature_bytes, pub_key)
        return True
    except rsa.VerificationError:
        return False


def decrypt_callback_ciphertext(associated_data, nonce, ciphertext):
    """
    使用APIv3密钥解密回调中的加密数据
    :param associated_data: 附加数据
    :param nonce: 随机串
    :param ciphertext: 密文（Base64）
    :return: 解密后的JSON字符串
    """
    api_v3_key = settings.WECHAT_PAY_V3_CONFIG['API_V3_KEY'].encode('utf-8')
    nonce_bytes = nonce.encode('utf-8')
    ciphertext_bytes = base64.b64decode(ciphertext)

    # AES-GCM解密
    cipher = AES.new(api_v3_key, AES.MODE_GCM, nonce=nonce_bytes)
    if associated_data:
        cipher.update(associated_data.encode('utf-8'))
    plaintext = cipher.decrypt_and_verify(ciphertext_bytes[:-16], ciphertext_bytes[-16:])
    return plaintext.decode('utf-8')'''

# utils/wechat_v3.py
import time
import hashlib
import base64
import json
from urllib.parse import urlparse

from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.backends import default_backend
from Crypto.Cipher import AES

from django.conf import settings
import os


def load_private_key():
    """加载私钥（支持 PKCS#1 和 PKCS#8）"""
    key_path = settings.WECHAT_PAY_V3_CONFIG['PRIVATE_KEY_PATH']
    with open(key_path, 'rb') as f:
        key_data = f.read()

    # cryptography 自动识别格式
    private_key = serialization.load_pem_private_key(
        key_data,
        password=None,
        backend=default_backend()
    )
    return private_key


def build_authorization(method, url, body):
    """生成V3接口的Authorization头"""
    private_key = load_private_key()
    mchid = settings.WECHAT_PAY_V3_CONFIG['MCHID']
    serial_no = settings.WECHAT_PAY_V3_CONFIG['CERT_SERIAL_NO']

    parsed = urlparse(url)
    path = parsed.path
    if parsed.query:
        path += '?' + parsed.query

    timestamp = str(int(time.time()))
    nonce = hashlib.md5((timestamp + 'wechat').encode()).hexdigest()[:32]

    # 构造签名串
    message = '\n'.join([method, path, timestamp, nonce, body]) + '\n'

    # 使用 cryptography 签名
    signature = private_key.sign(
        message.encode('utf-8'),
        padding.PKCS1v15(),
        hashes.SHA256()
    )
    signature_b64 = base64.b64encode(signature).decode('utf-8')

    auth = f'WECHATPAY2-SHA256-RSA2048 mchid="{mchid}",nonce_str="{nonce}",timestamp="{timestamp}",serial_no="{serial_no}",signature="{signature_b64}"'
    return auth


def verify_wechat_sign(headers, body):
    """验证微信回调签名（需提前下载平台证书）"""
    # 这部分使用 rsa 库验签，也可以改用 cryptography，但 rsa 已足够
    import rsa
    serial = headers.get('Wechatpay-Serial')
    signature = headers.get('Wechatpay-Signature')
    timestamp = headers.get('Wechatpay-Timestamp')
    nonce = headers.get('Wechatpay-Nonce')

    if not all([serial, signature, timestamp, nonce]):
        return False

    message = '\n'.join([timestamp, nonce, body]) + '\n'
    cert_path = f"{settings.WECHAT_PAY_V3_CONFIG['PLATFORM_CERT_DIR']}/{serial}.pem"
    if not os.path.exists(cert_path):
        return False

    with open(cert_path, 'rb') as f:
        pub_key = rsa.PublicKey.load_pkcs1_openssl_pem(f.read())

    signature_bytes = base64.b64decode(signature)
    try:
        rsa.verify(message.encode('utf-8'), signature_bytes, pub_key)
        return True
    except rsa.VerificationError:
        return False


def decrypt_callback_ciphertext(associated_data, nonce, ciphertext):
    """解密回调数据（使用 AES-GCM）"""
    api_v3_key = settings.WECHAT_PAY_V3_CONFIG['API_V3_KEY'].encode('utf-8')
    nonce_bytes = nonce.encode('utf-8')
    ciphertext_bytes = base64.b64decode(ciphertext)

    cipher = AES.new(api_v3_key, AES.MODE_GCM, nonce=nonce_bytes)
    if associated_data:
        cipher.update(associated_data.encode('utf-8'))
    plaintext = cipher.decrypt_and_verify(ciphertext_bytes[:-16], ciphertext_bytes[-16:])
    return plaintext.decode('utf-8')