<?php

/*
 * This file is part of the overtrue/wechat.
 *
 * (c) overtrue <i@overtrue.me>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */
namespace EasyWeChat\Payment\Kernel;

use EasyWeChat\Kernel\Support;
use EasyWeChat\Kernel\Traits\HasHttpRequests;
use EasyWeChat\Payment\Application;
use GuzzleHttp\MessageFormatter;
use GuzzleHttp\Middleware;
use Psr\Http\Message\ResponseInterface;
/**
 * Class BaseClient.
 *
 * @author overtrue <i@overtrue.me>
 */
class BaseClient
{
    use HasHttpRequests {
        request as performRequest;
    }
    /**
     * @var \EasyWeChat\Payment\Application
     */
    protected $app;
    /**
     * Constructor.
     *
     * @param \EasyWeChat\Payment\Application $app
     */
    public function __construct(Application $app)
    {
        $this->app = $app;
        $this->setHttpClient($this->app['http_client']);
    }
    /**
     * Extra request params.
     *
     * @return array
     */
    protected function prepends()
    {
        return [];
    }
    /**
     * Make a API request.
     *
     * @param $endpoint
     * @param array  $params
     * @param $method
     * @param array  $options
     * @param   $returnResponse
     *
     * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string
     *
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    protected function request($endpoint, array $params = [], $method = 'post', array $options = [], $returnResponse = false)
    {
        $base = ['mch_id' => $this->app['config']['mch_id'], 'nonce_str' => uniqid(), 'sub_mch_id' => $this->app['config']['sub_mch_id'], 'sub_appid' => $this->app['config']['sub_appid']];
        $params = array_filter(array_merge($base, $this->prepends(), $params), 'strlen');
        $secretKey = $this->app->getKey($endpoint);
        $encryptMethod = Support\get_encrypt_method(Support\Arr::get($params, 'sign_type', 'MD5'), $secretKey);
        $params['sign'] = Support\generate_sign($params, $secretKey, $encryptMethod);
        $options = array_merge(['body' => Support\XML::build($params)], $options);
        $this->pushMiddleware($this->logMiddleware(), 'log');
        $response = $this->performRequest($endpoint, $method, $options);
        return $returnResponse ? $response : $this->castResponseToType($response, $this->app->config->get('response_type'));
    }
    /**
     * Log the request.
     *
     * @return \Closure
     */
    protected function logMiddleware()
    {
        $formatter = new MessageFormatter(isset($this->app['config']['http.log_template']) ? $this->app['config']['http.log_template'] : MessageFormatter::DEBUG);
        return Middleware::log($this->app['logger'], $formatter);
    }
    /**
     * Make a request and return raw response.
     *
     * @param $endpoint
     * @param array  $params
     * @param $method
     * @param array  $options
     *
     * @return ResponseInterface
     *
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    protected function requestRaw($endpoint, array $params = [], $method = 'post', array $options = [])
    {
        /** @var ResponseInterface $response */
        $response = $this->request($endpoint, $params, $method, $options, true);
        return $response;
    }
    /**
     * Make a request and return an array.
     *
     * @param $endpoint
     * @param array  $params
     * @param $method
     * @param array  $options
     *
     * @return array
     *
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    protected function requestArray($endpoint, array $params = [], $method = 'post', array $options = [])
    {
        $response = $this->requestRaw($endpoint, $params, $method, $options);
        return $this->castResponseToType($response, 'array');
    }
    /**
     * Request with SSL.
     *
     * @param $endpoint
     * @param array  $params
     * @param $method
     * @param array  $options
     *
     * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string
     *
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    protected function safeRequest($endpoint, array $params, $method = 'post', array $options = [])
    {
        $options = array_merge(['cert' => $this->app['config']->get('cert_path'), 'ssl_key' => $this->app['config']->get('key_path')], $options);
        return $this->request($endpoint, $params, $method, $options);
    }
    /**
     * Wrapping an API endpoint.
     *
     * @param $endpoint
     *
     * @return string
     */
    protected function wrap($endpoint)
    {
        return $this->app->inSandbox() ? "sandboxnew/{$endpoint}" : $endpoint;
    }
}