<?php

namespace app\index\pay;

use think\Db;

class Goldbodipay extends PayBase
{
    const PAY_URL = 'https://api.goldbodi.com/gateway/api/h5apipay';
    //const PAYOUT_URL = 'http://transfer.51dianshangbao.com/index.php?/transfer';
    const PAYOUT_URL = 'https://transfer.goldbodi.com/transfer';

    public static function instance()
    {
        return new self();
    }

    public function getConfig($param)
    {
        if ($param == 'service_type') {
            $type = input('get.type/d', 0);
            if ($type > 0) {
                return config('pay.goldbodipay.t' . $type . '.' . $param);
            }
        }
        return config('pay.goldbodipay.' . $param);
    }

    public function get_mch_id()
    {
        return $this->getConfig('mch_id');
    }

    public function get_secret()
    {
        return $this->getConfig('secret');
    }

    //发起代收订单
    public function createPay(array $op_data): array
    {
        $oUser = Db::name('xy_users')->where('id', $op_data['uid'])->find();
        $userName = preg_replace("/\\d+/", '', $oUser['username']);
        if (!$userName) $userName = $this->randUsername();
        $data = [
            'merchant_code' => $this->get_mch_id(),
            'service_type' => $this->getConfig('service_type'),
            'interface_version' => "V3.1",
            'client_ip' => request()->ip(),
            'order_no' => $op_data['sn'],
            'order_time' => date('Y-m-d H:i:s'),
            'product_name' => $op_data['sn'],
            'order_amount' => sprintf("%.2f", $op_data['amount']),
            'notify_url' => url('/index/callback/pay', [
                'gateway' => (new \ReflectionClass(__CLASS__))->getShortName(),
                'type' => input('get.type/d', 0)
            ], true, true),
            'return_url' => url('/index/my/index', '', true, true),
            'extend_param' => 'customer_email^' . $oUser['tel'] . '@gmail.com|'
                . 'customer_name^' . $userName . '|'
                . 'customer_phone^' . $oUser['tel']
        ];
        /*if (input('get.type/d', 0) == 2) {
            $data['pay_type'] = 'payid';
        }*/
        $data['sign'] = $this->_make_sign($data);
        $data['sign_type'] = "RSA-S";
        $res = $this->_post(self::PAY_URL, $data);
        $xml = simplexml_load_string($res);
        if (isset($xml->response->resp_code) && isset($xml->response->payURL) &&
            $xml->response->resp_code == 'SUCCESS' && $xml->response->result_code == 0) {
            $url = urldecode($xml->response->payURL);
            return [
                'respCode' => 'SUCCESS',
                'payInfo' => $url,
            ];
        }
        return [
            'respCode' => 'ERROR',
            'payInfo' => '',
            'resData' => $res,
            'xmlData' => $xml,
            'postData' => $data
        ];
    }

    /**
     * 验证代收回调
     * @param string $type
     * @return array ['status'=>'SUCCESS',oid=>'订单号',amount=>'金额','data'=>'原始数据 array']
     */
    public function parsePayCallback($type = ''): array
    {
        $put = file_get_contents('php://input');
        parse_str($put, $data);
        //$data = json_decode($put, true);
        if (!isset($data['sign'])) {
            exit();
        }
        $check = $this->_check_callback_sign($data);
        if (!$check) {
            return ['status' => 'FAIL', 'msg' => '签名错误', 'data' => $data];
        }
        return [
            'status' => ($data['trade_status'] == 'SUCCESS' ? 'SUCCESS' : 'FAIL'),
            'oid' => $data['order_no'],
            'amount' => $data['order_amount'],
            'data' => $data,
            'msg' => !empty($data['trade_desc']) ? $data['trade_desc'] : '',
        ];
    }

    public function payCallbackSuccess()
    {
        echo 'OK';
    }

    public function payCallbackFail()
    {
        echo 'ERROR';
    }

    public $_payout_msg = '';

    public function create_payout(array $oinfo, array $blank_info): bool
    {
        $data = [
            'interface_version' => "V3.1.0",
            'tran_code' => 'DMTI',
            'merchant_no' => $this->get_mch_id(),

            'apply_type' => 'bank',
            'mer_transfer_no' => $oinfo['id'],
            'tran_amount' => sprintf("%.2f", $oinfo['num']),
            'tran_fee_type' => 1,
            'tran_type' => 1,

            'ifsc' => $blank_info['document_id'],
            'recv_bank_name' => $blank_info['document_type'],
            'recv_name' => $blank_info['username'],
            'recv_accno' => $blank_info['cardnum'],
            'recv_phone' => $blank_info['tel'],
            'recv_email' => $blank_info['document_id'],
            'recv_address' => 'shop',
            //墨西哥
            //'recv_email' => 'hzw@gmail.com',
            //'recv_bank_name' => $blank_info['bank_code'],


            'notify_url' => url('/index/callback/payout', [
                'gateway' => (new \ReflectionClass(__CLASS__))->getShortName(),
            ], true, true),
        ];
        if (config('default_country') == 'BRA') {
            $data['recv_accno'] = $blank_info['document_id'];
        }
        if (config('default_country') == 'MEX') {
            $data['ifsc'] = 'IOBA0001728';
            $data['recv_email'] = 'hzw@gmail.com';
            $data['recv_bank_name'] = $blank_info['bank_code'];
        }
        /*if ($oinfo['type'] == 'wallet') {
            $data['recv_bank_code'] = 'payid';
            $data['recv_accno'] = $blank_info['document_id'];
        }*/
        $data['sign_info'] = $this->_make_payout_sign($data);
        $data['sign_type'] = "RSA-S";
        $res = $this->_post(self::PAYOUT_URL, $data);
        $xml = simplexml_load_string($res);
        //print_r($data);
        //print_r($xml);
        //exit;
        if (isset($xml->result_code)
            && $xml->result_code == 0
            && $xml->recv_code == '0001') {
            return true;
        }
        $log_file = APP_PATH . 'goldbodipay_callback.log';
        file_put_contents($log_file, date('Y-m-d H:i:s') . ' ' . json_encode($data) . "\n", FILE_APPEND);
        $this->_payout_msg = !empty($xml->recv_info) ? $xml->recv_info : json_encode($xml);
        return false;
    }

    //["status"=>"SUCCESS","oid"=>"订单号","amount"=>"支付金额"]
    public function parsePayoutCallback($type = ''): array
    {
        $put = file_get_contents('php://input');
        parse_str($put, $data);
        if (!isset($data['sign_info']) || !isset($data['recv_code'])) {
            exit();
        }
        if ($data['recv_code'] == '0001') {
            exit();
        }
        $check = $this->_check_payout_callback_sign($data);
        if (!$check) {
            exit('sign error');
            return ['status' => 'FAIL', 'msg' => '签名错误', 'data' => $data];
        }
        return [
            'status' => ($data['recv_code'] == '0000' ? 'SUCCESS' : 'FAIL'),
            'oid' => $data['mer_transfer_no'],
            'amount' => $data['tran_amount'],
            //'msg' => !empty($data['recv_info']) ? $data['recv_info'] : '',
            'msg' => !empty($data['transfer_no']) ? $data['transfer_no'] : '',
            'data' => $data
        ];
    }

    public function parsePayoutCallbackFail()
    {
        echo "ERROR";
    }

    public function parsePayoutCallbackSuccess()
    {
        echo "OK";
    }


    private function decode($str)
    {
        $privateKey = $this->getConfig('private');
        openssl_private_decrypt(base64_decode($str), $decrypted, $privateKey);
        return $decrypted;
    }

    /**
     * 创建签名
     * @param $data array  数据包
     * @return string
     */
    private function _make_sign(array $data): string
    {
        ksort($data);
        $str = '';
        foreach ($data as $key => $value) {
            $value = trim($value);
            if (strlen($value) > 0) $str .= $key . '=' . $value . '&';
        }
        $str = substr($str, 0, -1);
        $merchant_private_key = $this->getConfig('private');
        $merchant_private_key = openssl_get_privatekey($merchant_private_key);
        openssl_sign($str, $sign_info, $merchant_private_key, OPENSSL_ALGO_MD5);
        $sign = base64_encode($sign_info);
        return $sign;
    }

    private function _check_callback_sign(array $data): string
    {
        ksort($data);
        $str = '';
        $sign_str = base64_decode($data['sign']);
        unset($data['sign']);
        unset($data['sign_type']);
        foreach ($data as $key => $value) {
            $value = trim($value);
            if (strlen($value) > 0) $str .= $key . '=' . $value . '&';
        }
        $str = substr($str, 0, -1);
        $dinpay_public_key = $this->getConfig('main_public');
        $dinpay_public_key = openssl_get_publickey($dinpay_public_key);
        $flag = openssl_verify($str, $sign_str, $dinpay_public_key, OPENSSL_ALGO_MD5);
        return $flag ? true : false;
    }

    private function _make_payout_sign(array $data): string
    {
        ksort($data);
        $str = '';
        foreach ($data as $key => $value) {
            $value = trim($value);
            if (strlen($value) > 0) $str .= $key . '=' . $value . '&';
        }
        $str = substr($str, 0, -1);
        $merchant_private_key = $this->getConfig('payout_private');
        $merchant_private_key = openssl_get_privatekey($merchant_private_key);
        openssl_sign($str, $sign_info, $merchant_private_key, OPENSSL_ALGO_MD5);
        $sign = base64_encode($sign_info);
        return $sign;
    }

    private function _check_payout_callback_sign(array $data): string
    {
        $str = '';
        $sign_str = base64_decode($data['sign_info']);
        unset($data['sign_info']);
        unset($data['sign_type']);
        ksort($data);
        foreach ($data as $key => $value) {
            $value = trim($value);
            if (strlen($value) > 0) $str .= $key . '=' . $value . '&';
        }
        $str = substr($str, 0, -1);
        $dinpay_public_key = $this->getConfig('payout_main_public');
        $dinpay_public_key = openssl_get_publickey($dinpay_public_key);
        $flag = openssl_verify($str, $sign_str, $dinpay_public_key, OPENSSL_ALGO_MD5);
        return $flag ? true : false;
    }
}