<?php

namespace App\Server\Payment;

use App\Model\BaseConfig;
use EasyWeChat\Factory;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Facades\Log;

/**
 * Class WeChatPay.
 *
 * @property \EasyWeChat\Payment\Application $app
 */
class WeChatPay extends PaymentProvider
{
    private $app;

    public function init()
    {
        $pay_config = BaseConfig::get('wechat_config');
        // try {
        $config = [
            'app_id'     => $pay_config['appId'],
            'mch_id'     => $pay_config['mchId'],
            'key'        => $pay_config['key'],   // API 密钥
            'cert_path'  => storage_path('app/public/apiclient_cert.pem'), // XXX: 绝对路径！！！！
            'key_path'   => storage_path('app/public/apiclient_key.pem'),      // XXX: 绝对路径！！！！
            'notify_url' => $pay_config['notifyUrl'] ?? env('APP_URL') . '/api/wxPayNotify',     // 你也可以在下单时单独设置来想覆盖它
            // 'notify_url'         => $pay_config['notifyUrl'],     // 你也可以在下单时单独设置来想覆盖它
        ];
        /*} catch (\Exception $e) {
            throw new \Exception('微信支付初始化失败：' . $e->getMessage());
        }*/
        $this->app = Factory::payment($config);
        if (!$this->app) {
            throw new \Exception('微信支付初始化失败，请检查配置');
        }
        if (isset($pay_config['is_sub']) && 1 == $pay_config['is_sub']) {
            $this->setSub();
        }
    }

    public function getApp()
    {
        return $this->app;
    }

    private function setSub()
    {
        $subMchId = BaseConfig::get('wechat_config', 'subMchId', '');
        $subAppId = BaseConfig::get('wechat_config', 'subAppId', '');
        $this->app->setSubMerchant($subMchId, $subAppId);
    }

    /**
     * 统一下单接口.
     *
     * @param float $money
     *
     * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
     */
    public function pay(string $out_trade_no, string $openId, int $money, string $title = '余额充值')
    {
        try {
            $result = $this->app->order->unify([
                'body'         => $title,
                'out_trade_no' => $out_trade_no,
                'total_fee'    => $money,
                'trade_type'   => 'JSAPI', // 请对应换成你的支付方式对应的值类型
                'openid'       => $openId,
            ]);
            if ('FAIL' == $result['return_code']) {
                return ['code' => 1, 'message' => "【微信支付】{$result['return_msg']}"];
            }
            $jssdk  = $this->app->jssdk;
            $config = $jssdk->sdkConfig($result['prepay_id']);

            return ['code' => 0, 'data' => $config];
        } catch (\Exception $e) {
            return ['code' => 1, 'message' => $e->getMessage()];
        } catch (GuzzleException $e) {
            return ['code' => 2, 'message' => $e->getMessage()];
        }
    }

    /**
     * 用户提现.
     *
     * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
     */
    public function cash(string $partner_trade_no, string $open_id, float $money)
    {
        try {
            $result = $this->app->transfer->toBalance([
                'partner_trade_no' => $partner_trade_no, // 商户订单号，需保持唯一性(只能是字母或者数字，不能包含有符号)
                'openid'           => $open_id,
                'check_name'       => 'NO_CHECK', // NO_CHECK：不校验真实姓名, FORCE_CHECK：强校验真实姓名
                // 're_user_name' => $real_name, // 如果 check_name 设置为FORCE_CHECK，则必填用户真实姓名
                'amount' => intval($money), // 企业付款金额，单位为分
                'desc'   => '用户提现', // 企业付款操作说明信息。必填
            ]);
            if ('SUCCESS' == $result['return_code'] && 'SUCCESS' == $result['result_code']) {
                return ['code' => 0, 'message' => 'success'];
            }
            Log::error('微信零钱提现金额：' . $money . '错误：' . json_encode($result));

            return ['code' => 3, 'message' => ''];
        } catch (\Exception $e) {
            return ['code' => 1, 'message' => $e->getMessage()];
        } catch (GuzzleException $e) {
            return ['code' => 2, 'message' => $e->getMessage()];
        }
    }

    public function payNotify()
    {
    }

    public function refund()
    {
        // TODO: Implement refund() method.
    }
}
