<?php

namespace app\common\library\payment;

use Alipay\EasySDK\Kernel\Factory;
use Alipay\EasySDK\Kernel\Config;
use app\common\exception\BaseException;
use app\common\model\Payment;
use think\facade\Db;
use think\facade\Request;

/**
 * @package app\common\library\payment
 * @class Alipay
 * @author xzncit 2024/3/16
 */
class Alipay {

    /**
     * @param $order
     * @return array|void
     * @throws BaseException
     */
    public function create($order) {
        if($order["terminal"] == 9){
            $domain = trim(Request::domain(),"/") . "/mobile";
            $returnUrl = $domain . "/pages/cart/info";
            return [
                "isPay"     => 2,
                "type"      => "alipay",
                "result"    => $this->wap($order["subject"], $order["order"], $domain, $returnUrl)
            ];
        }else if(in_array($order["terminal"],[10,11])){
            return [
                "isPay"  => 2,
                "type"   => "alipay",
                "params" => $this->app($order["subject"], $order["order"])
            ];
        }
    }

    /**
     * 手机wap支付
     * @param $subject
     * @param $order
     * @param $quitUrl
     * @param $returnUrl
     * @param $autoForm
     * @return array|string|string[]
     * @throws BaseException
     */
    public function wap($subject, $order, $quitUrl,$returnUrl,$autoForm = false){
        Factory::setOptions($this->config());
        $alipay = Factory::payment()->wap()->asyncNotify(url("api/payment.alipay/index",[],false,true))->pay($subject, $order["out_trade_no"],$order["order_amount"],$quitUrl,$returnUrl);
        return !$autoForm ? str_replace("<script>document.forms['alipaysubmit'].submit();</script>","",$alipay->body) : $alipay->body;
    }

    /**
     * APP支付
     * @param $subject
     * @param $order
     * @return string
     * @throws BaseException
     */
    public function app($subject, $order){
        Factory::setOptions($this->config());
        $alipay = Factory::payment()->app()->asyncNotify(url('api/payment.alipay/index', [], false, true))->pay($subject, $order["out_trade_no"],$order["order_amount"]);
        return $alipay->body;
    }

    /**
     * 退款
     * @param $out_trade_no
     * @param $amount
     * @return \Alipay\EasySDK\Payment\Common\Models\AlipayTradeRefundResponse
     * @throws BaseException
     */
    public function refund($out_trade_no,$amount){
        Factory::setOptions($this->config());
        $result = Factory::payment()->common()->refund($out_trade_no, $amount);
        return $result;
    }

    /**
     * 支付回调通知验证
     * @param $data
     * @return bool
     * @throws BaseException
     */
    public function verifyNotify($data){
        Factory::setOptions($this->config());
        return Factory::payment()->common()->verifyNotify($data);
    }

    /**
     * @return string
     */
    public function notify(){
        try{
            $output = array_merge($_POST,$_GET);
            if($this->verifyNotify($output)){
                throw new BaseException("验证签名出错",0);
            }

            if(empty($output["out_trade_no"])){
                throw new BaseException("订单号为空",0);
            }

            Db::startTrans();
            Order::pay($output);
            Db::commit();
            return $this->success();
        }catch (\Exception $ex){
            return $this->failure();
        }
    }

    public function config(){
        $alipay = Payment::where("code","alipay")->find();
        if(empty($alipay["config"])){
            throw new BaseException("请配置支付宝支付",0);
        }

        $array = json_decode($alipay["config"],true);
        $options = new Config();
        $options->protocol = 'https';
        $options->gatewayHost = 'openapi.alipay.com';
        $options->signType = 'RSA2';

        $options->appId = trim($array["appid"]);

        // 为避免私钥随源码泄露，推荐从文件中读取私钥字符串而不是写入源码中
        $options->merchantPrivateKey = trim($array["private_key"]);

        //注：如果采用非证书模式，则无需赋值上面的三个证书路径，改为赋值如下的支付宝公钥字符串即可
        $options->alipayPublicKey    = trim($array["public_key"]);
        return $options;
    }

    public function success(){
        return "success";
    }

    public function failure(){
        return "failure";
    }

}