<?php

namespace app\api\service;

use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Util\PemUtil;
use think\facade\Config;
use think\facade\Log;
use veitool\qrcode\QRcode;
use WeChatPay\Formatter;
use WeChatPay\Crypto\AesGcm;
use think\Response;


class WeChatPayService
{
    protected $instance;


    public function __construct()
    {
        $config = Config::get('pay.wechat.default');


        // 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名
        $merchantPrivateKeyFilePath = 'file://' . $config['private_key_path'];
        $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);

        // 「商户API证书」的「证书序列号」

        //从本地文件中加载「微信支付公钥」，用来验证微信支付应答的签名
        $platformPublicKeyFilePath = 'file://' . $config['publick_key_path'];
        $twoPlatformPublicKeyInstance = Rsa::from($platformPublicKeyFilePath, Rsa::KEY_TYPE_PUBLIC);
        // halt($merchantPrivateKeyInstance);
        // 「微信支付公钥」的「微信支付公钥ID」
        // 需要在 商户平台 -> 账户中心 -> API安全 查询
        $platformPublicKeyId = $config['publick_key_id'];

        // 从本地文件中加载「微信支付平台证书」，可由内置CLI工具下载到，用来验证微信支付应答的签名
        $platformCertificateFilePath = 'file://' . $config['wechatpay_platform_path'];
        $onePlatformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
        $wechatpay_platform_id = $config['wechatpay_platform_id'];

        // 构造一个APIv3的客户端实例
        $this->instance = Builder::factory([
            'mchid' => $config['mchid'],
            'serial' => $config['serial_no'],
            'privateKey' => $merchantPrivateKeyInstance,

            'certs' => [
                $wechatpay_platform_id => $onePlatformPublicKeyInstance,
                $platformPublicKeyId => $twoPlatformPublicKeyInstance,
            ],
        ]);

        // try {
        //     $resp = $this->instance->chain('v3/certificates')->get(
        //         /** @see https://docs.guzzlephp.org/en/stable/request-options.html#debug */
        //         // ['debug' => true] // 调试模式
        //     );
        //     echo (string) $resp->getBody(), PHP_EOL;
        // } catch(\Exception $e) {
        //     // 进行异常捕获并进行错误判断处理
        //     echo $e->getMessage(), PHP_EOL;
        //     if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
        //         $r = $e->getResponse();
        //         echo $r->getStatusCode() . ' ' . $r->getReasonPhrase(), PHP_EOL;
        //         echo (string) $r->getBody(), PHP_EOL, PHP_EOL, PHP_EOL;
        //     }
        //     echo $e->getTraceAsString(), PHP_EOL;
        // }
        // exit();

    }


    private function loadPlatformCertificates()
    {
        // 获取当前所有平台证书
        $certificates = $this->instance->v3->certificates->get();
        // halt($certificates['data']);
        foreach ($certificates['data'] as $cert) {
            // 解密证书
            $plainCert = AesGcm::decrypt(
                $cert['encrypt_certificate']['ciphertext'],
                config('pay.wechat.default.apiv3_key'),
                $cert['encrypt_certificate']['nonce'],
                $cert['encrypt_certificate']['associated_data']
            );

            // 解析序列号和公钥
            $serialNo = $cert['serial_no'];
            $publicKey = Rsa::from($plainCert, Rsa::KEY_TYPE_PUBLIC);

            // 添加到配置
            $this->instance->getConfig()->set('certs', [
                $serialNo => $publicKey
            ]);
        }
    }


    /**
     * 创建扫码支付订单
     * @param string $outTradeNo 商户订单号
     * @param int $amount 金额(分)
     * @param string $description 商品描述
     * @return array
     */
    public function createNativeOrder($outTradeNo, $amount, $description)
    {
        $config = Config::get('pay.wechat.default');

        try {
            $resp = $this->instance
                ->chain('v3/pay/transactions/native')
                ->post(['json' => [
                    'mchid' => $config['mchid'],
                    'appid' => $config['appid'],
                    'description' => $description,
                    'out_trade_no' => $outTradeNo,
                    'notify_url' => $config['notify_url'],
                    'amount' => [
                        'total' => (int)$amount,
                        'currency' => 'CNY',
                    ],
                ]]);
            $body = json_decode((string)$resp->getBody(), true);
            $codeUrl = $body['code_url']; // 提取支付链接
            $qr = new QRcode();
            $qr_image = $qr->png($codeUrl)->getBase64();

            return [
                'code' => 1,
                'data' => [
                    'code_url' => $codeUrl, // 支付链接
                    'qr_image' => $qr_image
                ]
            ];
        } catch (\Exception $e) {
            // halt($e->getCode());
            return ['code' => 0, 'msg' => $e->getMessage()];
        }
    }

    /**
     * 处理支付通知
     */
    public function handleNotify()
    {
        try {
            $config = Config::get('pay.wechat.default');

            // 获取微信回调的原始数据
            $inWechatpaySignature = request()->header('Wechatpay-Signature');
            $inWechatpayTimestamp = request()->header('Wechatpay-Timestamp');
            $inWechatpaySerial = request()->header('Wechatpay-Serial');
            $inWechatpayNonce = request()->header('Wechatpay-Nonce');
            $header = request()->header();
            $body = file_get_contents('php://input');

            Log::info('微信支付回调原始数据: ' . json_encode([
                    'headers' => [
                        'Wechatpay-Signature' => $inWechatpaySignature,
                        'Wechatpay-Timestamp' => $inWechatpayTimestamp,
                        'Wechatpay-Serial' => $inWechatpaySerial,
                        'Wechatpay-Nonce' => $inWechatpayNonce
                    ],
                    'body' => $body
                ]));

            $apiv3Key = $config['apiv3_key'];

            $platformPublicKeyInstance = Rsa::from('file://' . $config['wechatpay_platform_path'], Rsa::KEY_TYPE_PUBLIC);

            $timeOffsetStatus = 300 >= abs(Formatter::timestamp() - (int)$inWechatpayTimestamp);
            $verifiedStatus = Rsa::verify(
                Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $body),
                $inWechatpaySignature,
                $platformPublicKeyInstance
            );
            if (!$verifiedStatus) {
//                throw new \Exception("签名验证失败：");
            }

            // 转换通知的JSON文本消息为PHP Array数组
            $inBodyArray = (array)json_decode($body, true);
            // 使用PHP7的数据解构语法，从Array中解构并赋值变量
            ['resource' => [
                'ciphertext' => $ciphertext,
                'nonce' => $nonce,
                'associated_data' => $aad
            ]] = $inBodyArray;
            // 加密文本消息解密
            $inBodyResource = AesGcm::decrypt($ciphertext, $apiv3Key, $nonce, $aad);
            // 把解密后的文本转换为PHP Array数组
            $inBodyResourceArray = (array)json_decode($inBodyResource, true);

            $res = $this->queryOrderByOutTradeNo($inBodyResourceArray['out_trade_no']);
            $res = json_decode($res, true);
            if ($res['trade_state'] == 'SUCCESS') {
                // 处理业务逻辑
                $res = PayService::handlePaymentNotify($inBodyResourceArray['out_trade_no'], $inBodyResourceArray);
                return $res;
            }else {
                return false;
            }

            // 返回成功响应
            return true;
        } catch (\Exception $e) {
            Log::error("微信支付回调失败：{$e->getMessage()}");
            return false;
        }


    }


    /**
     * 根据商户订单号查询支付订单
     * @param string $outTradeNo 商户订单号
     * @return array
     * @throws \Exception
     */
    public function queryOrderByOutTradeNo(string $outTradeNo)
    {
        try {
            $resp = $this->instance
                ->chain("v3/pay/transactions/out-trade-no/{$outTradeNo}?mchid=" . Config::get('pay.wechat.default.mchid'))
                ->get(['mchid' => Config::get('pay.wechat.default.mchid')]);
            // 如果是 PSR-7 响应，获取错误详情
            if (method_exists($resp, 'getStatusCode') && $resp->getStatusCode() !== 200) {
                $errorBody = $resp->getBody()->getContents();
                Log::error("微信支付 API 返回错误：", json_decode($errorBody, true));
                throw new \Exception("微信支付返回错误：" . $errorBody);
            }

            return $resp->getBody()->getContents();
        } catch (\Throwable $e) {
            Log::error("微信支付订单查询失败：{$e->getMessage()}");
            throw new \Exception("订单查询失败：" . $e->getMessage());
        }
    }


    /**
     * 验证微信支付签名
     */
    private function verifySign($signature, $timestamp, $nonce, $body): bool
    {
        // 微信支付平台证书序列号（需提前获取并保存）
        $wechatpaySerial = '微信支付平台证书序列号';

        // 构造验签名串
        $message = "{$timestamp}\n{$nonce}\n{$body}\n";

        // 获取微信支付平台证书（需提前下载并保存）
        $publicKey = file_get_contents(root_path() . 'cert/wechatpay_public_key.pem');

        // 验证签名
        $result = openssl_verify(
            $message,
            base64_decode($signature),
            $publicKey,
            'sha256WithRSAEncryption'
        );

        return $result === 1;
    }

    /**
     * 解密数据
     */
    private function decryptData($ciphertext, $nonce, $associatedData): ?string
    {
        // APIv3密钥
        $apiKey = '你的APIv3密钥';

        try {
            $ciphertext = base64_decode($ciphertext);
            if (strlen($ciphertext) <= 16) {
                return null;
            }

            // 解密算法
            $ctext = substr($ciphertext, 0, -16);
            $authTag = substr($ciphertext, -16);

            return openssl_decrypt(
                $ctext,
                'aes-256-gcm',
                $apiKey,
                OPENSSL_RAW_DATA,
                $nonce,
                $authTag,
                $associatedData
            );
        } catch (\Exception $e) {
            Log::error('解密微信支付回调数据失败: ' . $e->getMessage());
            return null;
        }
    }


}