<?php

namespace JsonRpc;

use GuzzleHttp\Exception\ServerException;
use JsonRpc\Exception\RpcServerException;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;

class Client
{
    /**
     * all configuration information
     * @var array
     */
    protected $config;

    /**
     * request id
     * @var string
     */
    protected $id;

    /**
     * @var \GuzzleHttp\Client
     */
    protected $http;

    /**
     * which server rpc call choose
     * @var array
     */
    protected $server_config;

    public function __construct($config)
    {
        $this->config = $config;
        $this->id = app('request')->header('X-Request-Id') ?: "no-x-request-id";
    }

    /**
     *
     * @param $k
     * @return $this
     */
    public function endpoint($k)
    {
        $this->server_config = $this->config['client'][$k];

        $default = [
            'app' => $k,
            'timeout' => 3,
            'allow_redirects' => false,
        ];

        $this->http = new \GuzzleHttp\Client(array_merge($default, $this->server_config));
        return $this;
    }

    /**
     * @param $name
     * @param $arguments
     * @throws RpcServerException
     * @return array
     */
    public function call($name, $arguments)
    {
        $payload = [
            'jsonrpc' => '2.0',
            'method' => $name,
            'params' => $arguments,
            'id' => $this->id(),
        ];
        return $this->post($payload);
    }

    /**
     * @param $name
     * @param $arguments
     * @return array
     * @throws RpcServerException
     */
    public function __call($name, $arguments)
    {
        return $this->call($name, $arguments);
    }

    /**
     * @param $payload
     * @throws RpcServerException
     * @return array
     */
    protected function post($payload)
    {
        try {

            $headers = [
                'X-Client-App' => $this->config['app'],
            ];
            app('rpc.logger')->info("client_request",array_merge($this->server_config, $payload));
            $resp = $this->http->request('POST', 'rpc/json-rpc-v2.json', [
                'headers' => $headers,
                'json' => $payload,
            ]);
        } catch (ServerException $e) {
            throw new RpcServerException($e->getMessage(), $e->getCode());
        }

        try {
            $body = \GuzzleHttp\json_decode($resp->getBody(), true);
            app('rpc.logger')->info("client_response",$body);
            if (empty($body)) {
                throw new RpcServerException('http response empty', 500);
            }
            if (isset($body['error']) && isset($body['error']['code']) && isset($body['error']['message'])) {
                $message = is_array($body['error']['message']) ? json_encode($body['error']['message']) : $body['error']['message'];
                throw new RpcServerException($message, $body['error']['code']);
            }

            return $body['result'];

        } catch (\InvalidArgumentException $e) {
            app('rpc.logger')->error('client_decode_error',array_merge($this->server_config, $payload));
            throw new RpcServerException('json decode error', -32700);
        }
    }

    /**
     * request id
     * @return int
     */
    protected function id()
    {
//        return  $this->id.'-'.time();
        return $this->id;
    }

}