<?php
//  ---------------------------------------------------------------------------------
//    _____   _             _                   _   _____
//   |  __ \ | |           | |    /\           (_) |  __ \
//   | |__) || |__    __ _ | |   /  \    _ __   _  | |__) |_ __  ___
//   |  ___/ | '_ \  / _` || |  / /\ \  | '_ \ | | |  ___/| '__|/ _ \
//   | |     | | | || (_| || | / ____ \ | |_) || | | |    | |  | (_) |
//   |_|     |_| |_| \__,_||_|/_/    \_\| .__/ |_| |_|    |_|   \___/
//                                      | |
//                                      |_|
//   PhalApi Pro 专业版
//   广州果创网络科技有限公司
//
//  ---------------------------------------------------------------------------------
//
//   一、协议的许可和权利
//    1. 您可以在完全遵守本协议的基础上，将本软件应用于商业用途；
//    2. 您可以在协议规定的约束和限制范围内修改本产品源代码或界面风格以适应您的要求；
//    3. 您拥有使用本产品中的全部内容资料、商品信息及其他信息的所有权，并独立承担与其内容相关的
//       法律义务；
//    4. 获得商业授权之后，您可以将本软件应用于商业用途，自授权时刻起，在技术支持期限内拥有通过
//       指定的方式获得指定范围内的技术支持服务；
//
//   二、协议的约束和限制
//    1. 未获商业授权之前，禁止将本软件用于商业用途（包括但不限于企业法人经营的产品、经营性产品
//       以及以盈利为目的或实现盈利产品）；
//    2. 未获商业授权之前，禁止在本产品的整体或在任何部分基础上发展任何派生版本、修改版本或第三
//       方版本用于重新开发；
//    3. 如果您未能遵守本协议的条款，您的授权将被终止，所被许可的权利将被收回并承担相应法律责任；
//
//   三、有限担保和免责声明
//    1. 本软件及所附带的文件是作为不提供任何明确的或隐含的赔偿或担保的形式提供的；
//    2. 用户出于自愿而使用本软件，您必须了解使用本软件的风险，在尚未获得商业授权之前，我们不承
//       诺提供任何形式的技术支持、使用担保，也不承担任何因使用本软件而产生问题的相关责任；
//    3. 广州果创网络科技有限公司不对使用本产品构建的商城中的内容信息承担责任，但在不侵犯用户隐
//       私信息的前提下，保留以任何方式获取用户信息及商品信息的权利；
//
//   有关本产品最终用户授权协议、商业授权与技术服务的详细内容，均由广州果创网络科技有限公司独家
//   提供。广州果创网络科技有限公司拥有在不事先通知的情况下，修改授权协议的权力，修改后的协议对
//   改变之日起的新授权用户生效。电子文本形式的授权协议如同双方书面签署的协议一样，具有完全的和
//   等同的法律效力。您一旦开始修改、安装或使用本产品，即被视为完全理解并接受本协议的各项条款，
//   在享有上述条款授予的权力的同时，受到相关的约束和限制。协议许可范围以外的行为，将直接违反本
//   授权协议并构成侵权，我们有权随时终止授权，责令停止损害，并保留追究相关责任的权力。
//
//  ---------------------------------------------------------------------------------

namespace Mall\Domain;

use PhalApi\Exception\BadRequestException;
use Mall\Model\Mall\Order as OrderModel;

use PayPalCheckoutSdk\Core\PayPalHttpClient;
use PayPalCheckoutSdk\Core\SandboxEnvironment;
use PayPalCheckoutSdk\Core\ProductionEnvironment;
use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
use PayPalCheckoutSdk\Orders\OrdersCaptureRequest;

/**
 * 支付领域类
 */
class Pay {

    /**
     * 统一发起支付
     */
    public function startPay($order_id, $pay_type = null) {
        $order = new Order();
        $orderInfo = $order->getOrderInfo($order_id);

        if (empty($orderInfo)) {
            throw new BadRequestException(\PhalApi\T('order not exists'));
        }

        if ($pay_type !== null && $pay_type != $orderInfo['pay_type']) {
            $order->updatePayType($orderInfo['id'], $pay_type);
        }
        $pay_type = $pay_type ? $pay_type : $orderInfo['pay_type'];

        $config = new Config();
        $payConfig = $config->getPayConfigDetail($pay_type);
        if (empty($payConfig)) {
            throw new BadRequestException(\PhalApi\T('pay config not exists'));
        }

        if ($orderInfo['order_status'] != OrderModel::ORDER_STATUS_NEW) {
            throw new BadRequestException(\PhalApi\T('do not repeat to pay order'));
        }

        $payDetail = null;
        if ($pay_type == 'cash') {
            // 取配置说明
            $payDetail = $payConfig['desc'];
        } else if ($pay_type == 'alipay') {
            $payDetail = $this->startPayGatewayAlipay($payConfig, $orderInfo);
        } else if ($pay_type == 'paypal') {
            //throw new BadRequestException(\PhalApi\T('TODO'));
            $payDetail = $this->startPayGatewayPaypal($payConfig, $orderInfo);
        } else {
            // 可扩展您的支付方式
            throw new BadRequestException(\PhalApi\T('unknow pay type'));
        }

        return array('pay_type' => $pay_type, 'pay_detail' => $payDetail);
    }

    private function get_http_type()
    {
        $http_type = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ? 'https://' : 'http://';
        return $http_type;
    }

    protected function getPayGatewayAlipay($payConfig, $orderInfo) {
        $config = array(
            'use_sandbox' => $payConfig['mode'] == 'sandbox' ? true : false, // 是否使用沙盒模式

            'app_id'    => $payConfig['app_id'], // '2016073100130857',
            'sign_type' => 'RSA2', // RSA  RSA2

            // 支付宝公钥字符串
            'ali_public_key' => $payConfig['alipay_public_key'],

            // 自己生成的密钥字符串
            'rsa_private_key' => $payConfig['rsa_private_key'],

            'limit_pay' => array(
                //'balance',// 余额
                //'moneyFund',// 余额宝
                //'debitCardExpress',//     借记卡快捷
                //'creditCard',//信用卡
                //'creditCardExpress',// 信用卡快捷
                //'creditCardCartoon',//信用卡卡通
                //'credit_group',// 信用支付类型（包含信用卡卡通、信用卡快捷、花呗、花呗分期）
            ), // 用户不可用指定渠道支付当有多个渠道时用“,”分隔

            // 与业务相关参数
            'notify_url' => $this->get_http_type() . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost') . '/pay_notify/alipay/index.php',
            'return_url' => $this->get_http_type() . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost') . '/platform/place-an-order/result?id=' . $orderInfo['order_id'],
        );
        return $config;
    }

    protected function startPayGatewayAlipay($payConfig, $orderInfo) {
        $config = $this->getPayGatewayAlipay($payConfig, $orderInfo);

        // 请求参数，完整参数见具体表格
        $payData = [
            'body'         => $orderInfo['order_name'] . ' x' . $orderInfo['num'] . ' x' . $orderInfo['product_expire_time_desc'],
            'subject'      => $orderInfo['order_name'],
            'trade_no'     => $orderInfo['order_id'],// 自己实现生成
            'time_expire'  => time() + 600, // 表示必须 600s 内付款
            'amount'       => $orderInfo['price'], // 微信沙箱模式，需要金额固定为3.01
            'return_param' => '',
            'client_ip'    => \PhalApi\Tool::getClientIp(), // 客户地址
            'goods_type'   => 0, // 商品主类型：0—虚拟类商品，1—实物类商品
        ];

        // 使用
        try {
            $client = new \Payment\Client(\Payment\Client::ALIPAY, $config);
            $res    = $client->pay(\Payment\Client::ALI_CHANNEL_WEB, $payData);
            return $res;
        } catch (\Exception $e) {
            throw new BadRequestException($e->getMessage());
        }
    }

    // 同步查询
    public function checkPay($orderInfo) {
        $pay_type = $orderInfo['pay_type'];

        if ($pay_type == 'alipay') {
            // 支付宝，等待异步通知
            return $orderInfo['order_status'] == OrderModel::ORDER_STATUS_NEW ? false : true;
        } else if ($pay_type == 'paypal') {
            // Paypal 
            $config = new Config();
            $payConfig = $config->getPayConfigDetail($pay_type);
            return $this->capturePaypalOrder($payConfig, $orderInfo);
        } else if ($pay_type == 'cash') {
            // 现金支付，等待人工确认
            return $orderInfo['order_status'] == OrderModel::ORDER_STATUS_NEW ? false : true;
        }
        return false;
    }

    // 异步通知
    public function alipayNotify() {
        //商户订单号
        $out_trade_no = $_REQUEST['out_trade_no'];

        //支付宝交易号
        $trade_no = $_REQUEST['trade_no'];

        //交易状态
        $trade_status = $_REQUEST['trade_status'];

        $order_id = $out_trade_no;
        $order = new Order();
        $orderInfo = $order->getOrderInfo($order_id);

        // 异步回调
        /** {"gmt_create":"2020-09-21 21:51:59","charset":"utf-8","gmt_payment":"2020-09-21 21:52:05","notify_time":"2020-09-21 21:52:05","subject":"条形码流量套餐","sign":"Ft2foWwm5D2jHEfxyKeWQuOTL\/mYJMv9lYs7QJePWEvog6BhA86S5ILhPHIAiOK0XQVW7m0zQykFxmT2Z0ksEe6W2G8KCpJz5\/8uThvMiFnGo0ie0sjcCNwZjNGEgs0+JcqJbHVJeKDeuhVnyStXeu31dvgCfhoxRw3R1Mdqy35HsPHWNyd8\/PZ7WTtZjhj5op+5XP7\/UWCWM3to4n+ihaMMrrlvGqWTVThR8T1FR+876Wmsw+kR0eUT\/qf5xD77TgmELMX1tqMHUjsyh1lJSwHDeKrQBJhUXumV+NCFNqbvrNij4rFkOcKf1Hwsyz6b\/4VJ1UAhyLtkuc3Yj9xJ3g==","buyer_id":"2088702081298409","body":"条形码流量套餐 x3 x1个月","invoice_amount":"0.01","version":"1.0","notify_id":"2020092100222215205098401426129802","fund_bill_list":"[{\"amount\":\"0.01\",\"fundChannel\":\"ALIPAYACCOUNT\"}]","notify_type":"trade_status_sync","out_trade_no":"2020091516064072546","total_amount":"0.01","trade_status":"TRADE_SUCCESS","trade_no":"2020092122001498401429957999","auth_app_id":"2021001143654222","receipt_amount":"0.01","point_amount":"0.00","buyer_pay_amount":"0.01","app_id":"2021001143654222","sign_type":"RSA2","seller_id":"2088702037902811"} **/

        \PhalApi\DI()->logger->info('Pay::alipayNotify()', $_REQUEST);

        if (empty($orderInfo)) {
            exit('no such order');
        }

        $configDomain = new Config();
        $payConfig = $configDomain->getPayConfigDetail($orderInfo['pay_type']);
        $config = $this->getPayGatewayAlipay($payConfig, $orderInfo);

        // 实例化继承了接口的类
        $callback = new PayNotify($orderInfo);
        // $callback->handle('', '', '', array()); die(); // debug

        try {
            $client = new \Payment\Client(\Payment\Client::ALIPAY, $config);
            $xml = $client->notify($callback);
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
        exit;

        // 同步回调
        /** /platform/pay/success?order_id=&charset=utf-8&out_trade_no=2020091516064072542&method=alipay.trade.page.pay.return&total_amount=0.01&sign=jCltjX9wMZhpKouIaI5c6ujoXOU%2BgBokNnw5eFg9oK8S0R6Nw9KMUJPGmPK65oPb2%2Bu%2F8Igj8gLlNXqUcZq3q6nxQ4VIESVF0I%2B4qNSJrL7IMHJtXvYBzrKQ54%2Bkf3tA0Fx6IVwMloPvQdcxBeWwyfmYyMe63Gd%2FK5t8cOuoe8Sdpp1oUWNb8Dw%2FFhXLetq6vXrESorGJQdRCkPrYl%2BMnMk3mYDKnMBufpN7hs2n9NB9u7C%2FAS2NYzUY92Jn5slF3VG04bi97i9Six8mPHeNKixAC1TEWPlSFAY%2FnUFAEc%2B0rZcw%2FGUuiIDvyslQrChyebdU615sjwKTJ2Rf5jh%2FwA%3D%3D&trade_no=2020092122001498401429474590&auth_app_id=2021001143654222&version=1.0&app_id=2021001143654222&sign_type=RSA2&seller_id=2088702037902811&timestamp=2020-09-21+21%3A27%3A3 **/
    }

    /** ----------------- Paypal ----------------- **/

    protected function startPayGatewayPaypal($payConfig, $orderInfo) {
        $client = $this->getPaypalClient($payConfig);

        // Construct a request object and set desired parameters
        // Here, OrdersCreateRequest() creates a POST request to /v2/checkout/orders
        $request = new OrdersCreateRequest();
        $request->prefer('return=representation');
        $request->body = [
            "intent" => "CAPTURE",
            "purchase_units" => [[
                "reference_id" => $orderInfo['order_id'],
                "amount" => [
                    "value" => round($orderInfo['price'] * 0.1465, 2), // 1人民币=0.1465美元
                    "currency_code" => "USD"
                ]
            ]],
            "application_context" => [
                'cancel_url' => $this->get_http_type() . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost') . '/platform/place-an-order/result?id=' . $orderInfo['order_id'],
                'return_url' => $this->get_http_type() . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost') . '/platform/place-an-order/result?id=' . $orderInfo['order_id'],
            ] 
        ];

        try {
            // Call API with your client and get a response for your call
            $response = $client->execute($request);

            // If call returns body in response, you can get the deserialized version from the result attribute of the response
            // print_r($response);

            /**
            PayPalHttp\HttpResponse Object
                (
                    [statusCode] => 201
                    [result] => stdClass Object
                    (
                        [id] => 33D891151S5840736
                        [intent] => CAPTURE
                        [status] => CREATED
                        [purchase_units] => Array
                        (
                            [0] => stdClass Object
                            (
                                [reference_id] => 2020091516064072543
                                [amount] => stdClass Object
                                (
                                    [currency_code] => USD
                                    [value] => 2.00
                                )

                                [payee] => stdClass Object
                                (
                                    [email_address] => sb-2bnq43270691@personal.example.com
                                    [merchant_id] => GXXTY4BYJ6VZQ
                                )

                            )

                        )

                        [create_time] => 2020-09-22T03:45:50Z
                        [links] => Array
                        (
                            [0] => stdClass Object
                            (
                                [href] => https://api.sandbox.paypal.com/v2/checkout/orders/33D891151S5840736
                                [rel] => self
                                [method] => GET
                            )

                            [1] => stdClass Object
                            (
                                [href] => https://www.sandbox.paypal.com/checkoutnow?token=33D891151S5840736
                                [rel] => approve
                                [method] => GET
                            )

                            [2] => stdClass Object
                            (
                                [href] => https://api.sandbox.paypal.com/v2/checkout/orders/33D891151S5840736
                                [rel] => update
                                [method] => PATCH
                            )

                            [3] => stdClass Object
                            (
                                [href] => https://api.sandbox.paypal.com/v2/checkout/orders/33D891151S5840736/capture
                                [rel] => capture
                                [method] => POST
                            )

                        )

                    )

                    [headers] => Array
                    (
                        [] => 
                        [Cache-Control] => max-age=0, no-cache, no-store, must-revalidate
                        [Content-Length] => 758
                        [Content-Type] => application/json
                        [Date] => Tue, 22 Sep 2020 03
                        [Paypal-Debug-Id] => e2fce4293842d
                        [Set-Cookie] => X-PP-SILOVER=name%3DLIVE3.WEB.1%26silo_version%3D880%26app%3Dapiplatformproxyserv%26TIME%3D1591643782%26HTTP_X_PP_AZ_LOCATOR%3Dsandbox.slc; Path=/; Domain=paypal.com; Expires=Tue, 22 Sep 2020 04
                    )

                )
            **/

            $result = $response->result;

            // update id
            $orderModel = new OrderModel();
            $orderModel->update($orderInfo['id'], array('third_payment_id' => $result->id));

            foreach ($result->links as $it) {
                if ($it->rel == 'approve') {
                    return $it->href;
                }
            }

            throw new BadRequestException('approve link not found');
        } catch (\Exception $ex) {
            throw new BadRequestException($ex->getMessage());
        }
    }

    public function capturePaypalOrder($payConfig, $orderInfo) {
        $client = $this->getPaypalClient($payConfig);

        // Here, OrdersCaptureRequest() creates a POST request to /v2/checkout/orders
        // $response->result->id gives the orderId of the order created above
        $request = new OrdersCaptureRequest($orderInfo['third_payment_id']);
        $request->prefer('return=representation');
        try {
            // Call API with your client and get a response for your call
            $response = $client->execute($request);

            // If call returns body in response, you can get the deserialized version from the result attribute of the response
            // print_r($response);

            if ($response->result->status == 'COMPLETED') {
                return true;
            }

            return false;
        } catch (\Exception $ex) {
            $exArr = json_decode($ex->getMessage(), true);
            \PhalApi\DI()->logger->error('Pay::capturePaypalOrder() Exception', $exArr);
            if (\PhalApi\DI()->debug) {
                throw new BadRequestException($exArr['message']);
            }
        }

        return false;
    }

    protected function getPaypalClient($payConfig) {
        // Creating an environment
        $clientId = $payConfig['client_id'];
        $clientSecret = $payConfig['secret_key'];

        $environment = $payConfig['mode'] == 'sandbox' ? new SandboxEnvironment($clientId, $clientSecret) : new ProductionEnvironment($clientId, $clientSecret);
        $client = new PayPalHttpClient($environment);

        return $client;
    }
}
