<?php

namespace App\Libs\Pay\Merchants;

use Exception;
use GuzzleHttp\Client;

/**
 * 银联支付
 */
class UnionPay implements PayMerchantInterface
{
    private $make_order_url = 'https://qr.chinaums.com/netpay-portal/webpay/pay.do';
    private $query_order_url = 'https://qr.chinaums.com/netpay-route-server/api/';
    private $msgType = 'WXPay.jsPay';
    private $signType = 'MD5';
    private $mid;
    private $tid;
    private $instMid;
    private $msgSrc;
    private $msgSrcId;
    private $key;


    public function __construct(array $config)
    {
        $this->mid = $config['mid'];
        $this->tid = $config['tid'];
        $this->instMid = $config['instMid'];
        $this->msgSrc = $config['msgSrc'];
        $this->msgSrcId = $config['msgSrcId'];
        $this->key = $config['key'];
    }

    public function send(array $data)
    {
        $result = [
            'mid' => $this->mid,
            'tid' => $this->tid,
            'instMid' => $this->instMid,
            'msgSrc' => $this->msgSrc,
            'msgSrcId' => $this->msgSrcId,
            'msgType' => $this->msgType,
            'signType' => $this->signType,
            'requestTimestamp' => date('Y-m-d H:i:s'),
            'notifyUrl' => env('UNIONPAY_NOFITY_URL'),
            'returnUrl' => $data['pay_wait_url'],
            'totalAmount' => $data['price'],
            'merOrderId' => $data['trade_no'],
        ];
        $result['sign'] = $this->makeSign($result);
        $query_params = http_build_query($result);
        return $this->make_order_url . '?' . $query_params;
    }

    public function query(string $trade_no)
    {
        $query_params = [
            'mid' => $this->mid,
            'tid' => $this->tid,
            'instMid' => $this->instMid,
            'msgSrc' => $this->msgSrc,
            'msgSrcId' => $this->msgSrcId,
            'signType' => $this->signType,
            'msgType' => 'query',
            'requestTimestamp' => date('Y-m-d H:i:s'),
            'merOrderId' => $trade_no,
        ];
        $result = $this->request($query_params);
        if (
            isset($result->errCode) && $result->errCode === 'SUCCESS' &&
            isset($result->status) && $result->status === 'TRADE_SUCCESS'
        ) {
            return true;
        } else {
            myLog("union_pay_query")->info(object_to_array($result));
        }
        return false;
    }

    public function notify(array $data)
    {
        if (isset($data['status']) && $data['status'] === 'TRADE_SUCCESS') {
            $sign = $this->makeSign($data);
            if ($sign === $data['sign']) {
                return true;
            }
        }
        return false;
    }

    public function refund(array $data)
    {
        $refund_params = [
            'mid' => $this->mid,
            'tid' => $this->tid,
            'instMid' => $this->instMid,
            'msgSrc' => $this->msgSrc,
            'msgSrcId' => $this->msgSrcId,
            'signType' => $this->signType,
            'msgType' => 'refund',
            'requestTimestamp' => date('Y-m-d H:i:s'),
            'merOrderId' => $data['trade_no'],
            'refundAmount' => $data['price'],
        ];
        $result = $this->request($refund_params);
        if (
            isset($result->errCode) && $result->errCode === 'SUCCESS' &&
            isset($result->refundStatus) && $result->refundStatus === 'SUCCESS' &&
            isset($result->status) && $result->status === 'TRADE_SUCCESS'
        ) {
            return true;
        } else {
            myLog("union_pay_refund")->info(object_to_array($result));
        }
        return false;
    }

    /**
     * 生成订单号
     */
    public function generateTradeNo()
    {
        return substr($this->msgSrcId . date("YmdHis") . hexdec(uniqid()), 0, 30);
    }

    public function makeSign(array $data)
    {
        //签名步骤一：按字典序排序参数
        ksort($data);
        $buff = "";
        foreach ($data as $k => $v) {
            if ($k != "sign" && $v != "" && !is_array($v)) {
                $buff .= $k . "=" . $v . "&";
            }
        }
        $buff = trim($buff, "&");
        //签名步骤二：在string后加入KEY
        $string = $buff . $this->key;
        //签名步骤三：MD5加密
        $string = md5($string);
        //签名步骤四：所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }

    private function request(array $data)
    {
        try {
            $data['sign'] = $this->makeSign($data);
            $client = new Client(['timeout' => 3]);
            $result = $client->request('post',  $this->query_order_url, ['json' => $data])->getBody()->getContents();
            if ($result) {
                $result = json_decode($result);
            }
            return $result;
        } catch (Exception $e) {
            myLog("union_pay_request")->info(object_to_array($result));
        }
    }
}
