<?php

namespace Extend\Wechat;

use App\Constants\HttpEnumCode;
use App\Exception\BusinessException;
use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
use EasyWeChat\Kernel\Exceptions\InvalidConfigException;
use EasyWeChat\OfficialAccount\Message;
use EasyWeChat\Pay\Application;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Utils\ApplicationContext;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\SimpleCache\CacheInterface;

/**
 * 微信支付类
 */
class WechatPay
{
    protected array $config;// 系统配置
    protected array $pay_config;// 支付系统配置
    protected string $pay_notify_url;// 支付回调地址
    protected string $refund_notify_url;// 退款回调地址

    /**
     * @param string $user_type 用户类型（1：患者端 2：专家端 3：药师端）
     * @param int $order_type 订单类型（1：问诊订单 2：药品订单）
     */
    public function __construct(string $user_type,int $order_type)
    {
        if ($user_type == 1){
            $this->config = config("we_chat.applets.patient");
        }elseif ($user_type == 2){
            $this->config = config("we_chat.applets.doctor");
        }elseif ($user_type == 3){
            $this->config = config("we_chat.applets.pharmacist");
        }

        $this->pay_config = config("we_chat.applets.pay");

        if (empty($this->config)){
            throw new BusinessException("系统配置错误", HttpEnumCode::SERVER_ERROR);
        }

        if (!in_array($order_type,[1,2])){
            throw new BusinessException("订单类型错误", HttpEnumCode::SERVER_ERROR);
        }

        if ($order_type == 1){
            $this->pay_notify_url = $this->config['inquiry_pay_notify_url'];
            $this->refund_notify_url = $this->config['inquiry_refund_notify_url'];
        }

        if ($order_type == 2){
            $this->pay_notify_url = $this->config['product_pay_notify_url'];
            $this->refund_notify_url = $this->config['product_refund_notify_url'];
        }
    }

    /**
     * 创建工厂类
     * @return Application
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public function createApp(): Application
    {
        $config = [
            'mch_id' => $this->pay_config['mch_id'],

            // 商户证书
            'private_key' => __DIR__ . '/certs/1636644248/apiclient_key.pem',
            'certificate' => __DIR__ . '/certs/1636644248/apiclient_cert.pem',

            // v3 API 秘钥
            'secret_key' => $this->pay_config['v3_api_secret'],

            // v2 API 秘钥
            'v2_secret_key' => '',

            // 平台证书：微信支付 APIv3 平台证书，需要使用工具下载
            // 下载工具：https://github.com/wechatpay-apiv3/CertificateDownloader
            'platform_certs' => [
                // 请使用绝对路径
                __DIR__ . '/certs/' . $this->pay_config['mch_id'] . '/wechatpay_112FCCD1B9ECC8292703AB7363C73D74B6AFDC1A.pem',
            ],

            /**
             * 接口请求相关配置，超时时间等，具体可用参数请参考：
             * https://github.com/symfony/symfony/blob/5.3/src/Symfony/Contracts/HttpClient/HttpClientInterface.php
             */
            'http' => [
                'throw'  => false, // 状态码非 200、300 时是否抛出异常，默认为开启
                'timeout' => 5.0,
                // 'base_uri' => 'https://api.mch.weixin.qq.com/', // 如果你在国外想要覆盖默认的 url 的时候才使用，根据不同的模块配置不同的 uri
            ],
        ];

        try {
            $app = new Application($config);
            $request = ApplicationContext::getContainer()->get(RequestInterface::class);
            $app->setRequest($request);
            return $app;
        } catch (InvalidArgumentException $e) {
            throw new BusinessException('实例化EasyWeChat类失败:' . $e->getMessage(), HttpEnumCode::SERVER_ERROR);
        }
    }

    /**
     * 获取jsapi预支付交易会话标识
     * @param string $out_trade_no 商户系统内部订单号
     * @param int $total 支付金额（实际金额x100）
     * @param string $openid
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public function getJsapiPrepayId(string $out_trade_no,int $total,string $openid): array
    {
        $app = $this->createApp();

        $options = [
            "mchid" => $this->pay_config['mch_id'], // <---- 商户号
            "out_trade_no" => $out_trade_no, // 商户系统内部订单号
            "appid" => $this->config['app_id'],
            "description" => "问诊服务",
            "notify_url" => env('DOMAIN_NAME_DEV') . $this->pay_notify_url,
            "amount" => [
                "total" => $total,//订单总金额，单位为分。
                "currency" => "CNY"
            ],
            "payer" => [
                "openid" => $openid // 下单用户的 openid
            ]
        ];

        try {
            $response = $app->getClient()->postJson("v3/pay/transactions/jsapi", $options);
            if ($response->isFailed()) {
                // 出错了，处理异常
                $result = $response->toArray(false);
                if(empty($result)){
                    // 返回值为空
                    throw new BusinessException("发起支付失败");
                }
                if (!empty($result['code'])){
                    throw new BusinessException($result['message']);
                }
                throw new BusinessException("发起支付失败");
            }

            return $response->toArray(false);
        } catch (\Exception $e) {
            throw new BusinessException($e->getMessage(), HttpEnumCode::SERVER_ERROR);
        }
    }

    /**
     * 获取小程序支付配置
     * @param string $prepay_id 预支付交易会话标识
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public function getAppletsPayConfig(string $prepay_id): array
    {

        try {
            $app = $this->createApp();
            $utils = $app->getUtils();

            $appId = $this->config['app_id'];
            $signType = 'RSA'; // 默认RSA，v2要传MD5

            $config = $utils->buildMiniAppConfig($prepay_id, $appId, $signType);
            if (empty($config)){
                throw new BusinessException("发起支付失败");
            }

            return $config;
        } catch (\Exception $e) {
            throw new BusinessException($e->getMessage(), HttpEnumCode::SERVER_ERROR);
        }
    }

    /**
     * 退款接口
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public function refund(array $options)
    {
        try {
            $app = $this->createApp();

            $options['notify_url'] = env('DOMAIN_NAME_DEV') . $this->refund_notify_url;

            $response = $app->getClient()->postJson("v3/refund/domestic/refunds", $options);
            if ($response->isFailed()) {
                // 出错了，处理异常
                $result = $response->toArray(false);
                if(empty($result)){
                    // 返回值为空
                    throw new BusinessException("发起退款失败");
                }
                if (!empty($result['code'])){
                    throw new BusinessException($result['message']);
                }
                throw new BusinessException("发起退款失败");
            }

            return $response->toArray(false);
        } catch (\Exception $e) {
            throw new BusinessException($e->getMessage(), HttpEnumCode::SERVER_ERROR);
        }
    }
}