<?php
namespace Payment\WeChatPayment;

use Payment\CLogFileHandler;
use Payment\Log;
use Payment\PaymentException;
use Payment\WeChatPayment\lib\JsApiPay;
use Payment\WeChatPayment\lib\WxPayApi;
use Payment\WeChatPayment\lib\WxPayAppPay;
use Payment\WeChatPayment\lib\WxPayNotify;
use Payment\WeChatPayment\lib\WxPayOrderQuery;
use Payment\WeChatPayment\lib\WxPayRefund;
use Payment\WeChatPayment\lib\WxPayUnifiedOrder;

class WxPayGenerator
{
    private $config;

    public function __construct($config)
    {
        //实例化配置类 并写入内部属性
        $this -> config = new WeChatPaymentConfiguration($config);
    }

    /**
     * 外部统一下单接口
     * @param array $params
     * @return mixed
     * @throws PaymentException
     */
    public function order(array $params)
    {
        //开启日志
        $logHandler= new CLogFileHandler($this ->config->GetLogPath());
        Log::Init($logHandler, 15);

        $input = new WxPayUnifiedOrder();
        $input->SetBody(strval($params['title']));
        $input->SetDetail($params['detail'] ?? '');
        $input->SetOut_trade_no(strval($params['out_trade_no']));
        $input->SetTotal_fee(intval($params['total_amount']));
        $input->SetTrade_type($params['trade_type']);
        $input->SetProduct_id($params['product_id'] ?? '');
        $input->SetOpenid($params['openid'] ?? '');
        $input->SetAttach($params['attach'] ?? '');
        if(isset($params['notify_url'])) $input->SetNotify_url($params['notify_url']);

        $input->SetTime_start(date("YmdHis"));
        //$input->SetTime_expire(date("YmdHis", time() + 300));

        return $this -> orderProcess($input);
    }


    /**
     * 外部调用订单查询接口
     * @param string $number
     * @return mixed
     * @throws PaymentException
     */
    public function query(string $number)
    {
        $input = new WxPayOrderQuery();
        $input -> SetOut_trade_no($number);
        $result = WxPayApi::orderQuery($this->config, $input);


        if($result['return_code'] !== 'SUCCESS')
        {
            throw new PaymentException($result['return_msg']);
        }
        if($result['result_code'] !== 'SUCCESS')
        {
            throw new PaymentException($result['err_code_des']);
        }

        return $result;
    }

    /**
     * 外部调用退款接口
     * @param array $params
     * @return mixed
     * @throws PaymentException
     */
    public function refund(array $params)
    {
        $logHandler= new CLogFileHandler($this -> config->GetLogPath().'/refund');
        Log::Init($logHandler, 15);

        $order_number = $params["order_number"];
        $total_fee = $params["total_fee"];
        $refund_fee = $params["refund_fee"];
        $refund_desc = $params["complain"];

        $input = new WxPayRefund();
        $input->SetOut_trade_no($order_number);
        $input->SetTotal_fee($total_fee);
        $input->SetRefund_fee($refund_fee);
        $input->setRefundDesc($refund_desc);
        $input->SetOut_refund_no("sdkphp".date("YmdHis"));
        $input->SetOp_user_id($this -> config -> GetMerchantId());

        $result = WxPayApi::refund($this -> config, $input);

        if($result['return_code'] !== 'SUCCESS')
        {
            throw new PaymentException($result['return_msg']);
        }
        if($result['result_code'] !== 'SUCCESS')
        {
            throw new PaymentException($result['err_code_des']);
        }

        return $result;
    }

    /**
     * 外部调用异步通知
     * @param object $class 控制器
     * @param callable $function 回调函数并包含异步通知数据
     */
    public function notify(callable $function)
    {
        $logHandler= new CLogFileHandler($this -> config->GetLogPath().'/notify');
        Log::Init($logHandler, 15);

        $notify = new WxPayNotify();
        $notify -> setCallBack($function);
        $notify -> Handle($this -> config,true);
    }


    /**
     * @param WxPayUnifiedOrder $input
     * @return array|bool
     * @throws PaymentException
     */
    protected function orderProcess(WxPayUnifiedOrder $input)
    {
        //调用内部统一下单
        $result = WxPayApi::unifiedOrder($this -> config, $input);
        if($result['return_code'] !== 'SUCCESS')
        {
            throw new PaymentException($result['return_msg']);
        }
        if($result['result_code'] !== 'SUCCESS')
        {
            throw new PaymentException($result['err_code_des']);
        }

        $trade_type = $result['trade_type'];
        $response = '';
        if($trade_type == 'APP')
        {
            $app = new WxPayAppPay();
            $app->SetAppid($result["appid"]);
            $timeStamp = time();
            $app->SetTimeStamp("$timeStamp");
            $app->SetNonceStr($result['nonce_str']);
            $app->SetPrepayId($result['prepay_id']);
            $app->SetPackage("Sign=WXPay");
            $app->SetPartnerId($this -> config->GetMerchantId());
            $app->SetSign($app->MakeSign($this -> config,false));

            $response = $app->GetValues();
        }
        if($trade_type == 'JSAPI')
        {
            $jsapi = new JsApiPay();
            $response = $jsapi -> GetJsApiParameters($result,$this -> config);
        }
        if($trade_type == 'NATIVE')
        {
            $response = $result['code_url'];
        }

        return $response;
    }
}