<?php
namespace boru\ai\Http;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;

class GuzzleHttpClient implements HttpClientInterface
{
    /** @var Client */
    protected $client;

    public function __construct(Client $client = null, array $config = array())
    {
        $this->client = $client ? $client : new Client($config);
    }

    public function send(HttpRequest $request)
    {
        $options = $request->options();

        if ($request->headers()) {
            $options['headers'] = $request->headers();
        }
        if ($request->json() !== null) {
            $options['json'] = $request->json();
        }
        if ($request->body() !== null) {
            $options['body'] = $request->body();
        }
        if ($request->multipart() !== null) {
            $options['multipart'] = $request->multipart();
        }

        if (!isset($options['http_errors'])) {
            $options['http_errors'] = false;
        }

        if ($request->streamCallback()) {
            $options['stream'] = true;
        }

        try {
            $psrResponse = $this->client->request($request->method(), $request->url(), $options);
        } catch (GuzzleException $e) {
            throw new \RuntimeException($e->getMessage(), (int)$e->getCode(), $e);
        }

        $response = new HttpResponse();
        $response->statusCode($psrResponse->getStatusCode());
        $response->headers($psrResponse->getHeaders());

        if ($request->streamCallback()) {
            $body = $psrResponse->getBody();
            $buffer = '';
            $readSize = (int)$request->option('stream_read_size');
            if ($readSize <= 0) {
                $readSize = 1024;
            }

            while (!$body->eof()) {
                $chunk = $body->read($readSize);
                if ($chunk === '') {
                    continue;
                }
                $buffer .= $chunk;
                call_user_func($request->streamCallback(), $chunk, $response);
            }

            $response->body($buffer);
            return $response;
        }

        $response->body((string)$psrResponse->getBody());
        return $response;
    }
}
