<?php

namespace Kuxin\Weixin;

use Kuxin\Config;
use Kuxin\Helper\Http;
use Kuxin\Helper\Json;
use Kuxin\Helper\Xml;
use Kuxin\Request;

class Pay extends Weixin
{
    const API_UNIFIED_ORDER = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
    const API_ORDER_QUERY = 'https://api.mch.weixin.qq.com/pay/orderquery';

    const TRADE_TYPE_JSAPI = 'JSAPI';
    const TRADE_TYPE_NATIVE = 'NATIVE';
    const TRADE_TYPE_MWEB = 'MWEB';

    public function unifiedorder($data, $tradeType = self::TRADE_TYPE_JSAPI)
    {
        $data         = array_merge([
            'appid'            => $this->appId,
            'mch_id'           => Config::get('weixin.mchid'),
            'nonce_str'        => $this->getNonceStr(),
            'notify_url'       => Config::get('weixin.notifyurl'),
            'spbill_create_ip' => $tradeType == self::TRADE_TYPE_NATIVE ? Config::get('server_ip', gethostbyname($_SERVER['SERVER_NAME'])) : Request::getIp(),
            'trade_type'       => $tradeType,
        ], $data);
        $data['sign'] = $this->makeSign($data);
        $xml          = Xml::encode($data);
        $res          = Http::post(self::API_UNIFIED_ORDER, $xml);
        if ($res) {
            $res = Xml::decode($res);
            if ($res['return_code'] != 'SUCCESS') {
                return $res['return_msg'];
            }
            if (isset($res['result_code']) && $res['result_code'] == 'FAIL') {
                return $res['err_code'] . ':' . $res['err_code_des'];
            }
            return $res;
        } else {
            return '统一下单请求失败';
        }
    }

    public function notify($data = null)
    {
        if (!$data) {
            $data = file_get_contents('php://input');
        }
        $data = Xml::decode($data);
        if (isset($data['return_code']) && $data['return_code'] == 'SUCCESS') {
            if ($data['sign'] == $this->makeSign($data)) {
                return [
                    'id'             => $data['out_trade_no'],
                    'is_subscribe'   => $data['is_subscribe'],
                    'openid'         => $data['openid'],
                    'attach'         => isset($data['attach']) ? $data['attach'] : "",
                    'time_end'       => strtotime($data['time_end']),
                    'transaction_id' => $data['transaction_id'],
                    'money'          => $data['total_fee'] / 100,
                ];
            } else {
                return '签名验证失败';
            }
        } else {
            return '解析数据失败';
        }
    }

    public function query($orderId)
    {
        $data         = [
            'appid'        => $this->appId,
            'mch_id'       => Config::get('weixin.mchid'),
            'out_trade_no' => $orderId,
            'nonce_str'    => $this->getNonceStr(),
        ];
        $data['sign'] = $this->makeSign($data);
        $xml          = Xml::encode($data);
        if ($res = Http::post(self::API_ORDER_QUERY, $xml)) {
            $res = Xml::decode($res);
            if ($res['return_code'] != 'SUCCESS') {
                return $res['return_msg'];
            }
            if (isset($res['result_code']) && $res['result_code'] == 'FAIL') {
                return $res['err_code'] . ':' . $res['err_code_des'];
            }
            return $res;
        } else {
            return '订单查询请求失败';
        }

    }

    public function jsPayConfig($prepay_id, $json = true)
    {
        $data            = [
            'appId'     => $this->appId,
            'timeStamp' => (string)$_SERVER['REQUEST_TIME'],
            'nonceStr'  => $this->getNonceStr(),
            'package'   => 'prepay_id=' . $prepay_id,
            'signType'  => 'MD5',
        ];
        $data['paySign'] = $this->makeSign($data);
        return $json ? Json::encode($data) : $data;
    }

    /**
     * 格式化参数格式化成url参数
     */
    public function toUrlParams($data)
    {
        $buff = "";
        foreach ($data as $k => $v) {
            if ($k != "sign" && $v != "" && !is_array($v)) {
                $buff .= $k . "=" . $v . "&";
            }
        }

        $buff = trim($buff, "&");
        return $buff;
    }

    /**
     * 生成签名
     *
     * @return string 签名，本函数不覆盖sign成员变量，如要设置签名需要调用SetSign方法赋值
     */
    public function makeSign($data)
    {
        //签名步骤一：按字典序排序参数
        ksort($data);
        $string = $this->toUrlParams($data);
        //签名步骤二：在string后加入KEY
        $string = $string . "&key=" . Config::get('weixin.paykey');
        //签名步骤三：MD5加密
        $string = md5($string);
        //签名步骤四：所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }

}