<?php

namespace Analyst\Http;

use Analyst\ApiResponse;
use Analyst\Contracts\HttpClientContract;

class CurlHttpClient implements HttpClientContract
{
	/**
	 * Make an http request
	 *
	 * @param $method
	 * @param $url
	 * @param array $body
	 * @param $headers
	 * @return mixed
	 */
	public function request($method, $url, $body, $headers)
	{
		$method = strtoupper($method);

		$options = [
			CURLOPT_RETURNTRANSFER => true,
			CURLOPT_URL => $url,
            CURLOPT_HTTPHEADER => $this->prepareRequestHeaders($headers),
			CURLOPT_CUSTOMREQUEST => $method,
			CURLOPT_FAILONERROR => true,
			CURLOPT_HEADER => true,
			CURLOPT_TIMEOUT => 30,
		];

		if ($method === 'POST') {
		    $options[CURLOPT_POST] = 1;
			$options[CURLOPT_POSTFIELDS] = json_encode($body);
		}

		$curl = curl_init();

		curl_setopt_array($curl, $options);

		$response = curl_exec($curl);

		list($rawHeaders, $rawBody) = explode("\r\n\r\n", $response, 2);

		$info = curl_getinfo($curl);

		curl_close($curl);

		$responseHeaders = $this->resolveResponseHeaders($rawHeaders);
		$responseBody = json_decode($rawBody, true);

		return new ApiResponse($responseBody, $info['http_code'], $responseHeaders);
	}

	/**
	 * Must return `true` if client is supported
	 *
	 * @return bool
	 */
	public static function hasSupport()
	{
		return function_exists('curl_version');
	}

    /**
     * Modify request headers from key value pair
     * to vector array
     *
     * @param array $headers
     * @return array
     */
	protected function prepareRequestHeaders ($headers)
    {
        return array_map(function ($key, $value) {
            return sprintf('%s:%s', $key, $value);
        }, array_keys($headers), $headers);
    }

	/**
	 * Resolve raw response headers as
	 * associative array
	 *
	 * @param $rawHeaders
	 * @return array
	 */
	private function resolveResponseHeaders($rawHeaders)
	{
		$headers = [];

		foreach (explode("\r\n", $rawHeaders) as $i => $line) {
			$parts = explode(': ', $line);

			if (count($parts) === 1) {
				continue;
			}

			$headers[$parts[0]] = $parts[1];
		}
		return $headers;
	}
}
