<?php

use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Handler\CurlHandler;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\RequestOptions;
use Psr\Http\Message\ResponseInterface as ResponseInterfaceAlias;

class _DevblocksHttpService {
	static $instance = null;
	private static $_client = null;
	
	private function __construct() {}
	
	static function getInstance() {
		if(null == self::$instance) {
			self::$instance = new _DevblocksHttpService();
		}
		
		return self::$instance;
	}
	
	private function _configure_defaults() {
		return function(callable $handler) {
			return function (RequestInterface $request, array $options) use ($handler) {
				if(!array_key_exists(RequestOptions::HTTP_ERRORS, $options))
					$options[RequestOptions::HTTP_ERRORS] = false;
				
				if(!array_key_exists(RequestOptions::CONNECT_TIMEOUT, $options))
					$options[RequestOptions::CONNECT_TIMEOUT] = 10;
				
				if(!array_key_exists(RequestOptions::TIMEOUT, $options))
					$options[RequestOptions::TIMEOUT] = 30;
				
				if(defined('DEVBLOCKS_HTTP_PROXY') && DEVBLOCKS_HTTP_PROXY) {
					$options[RequestOptions::PROXY] = [
						'http' => DEVBLOCKS_HTTP_PROXY,
						'https' => DEVBLOCKS_HTTP_PROXY,
					];
				}
				return $handler($request, $options);
			};
		};
	}
	
	function getClient() : GuzzleHttp\Client {
		if(self::$_client)
			return self::$_client;
		
		$handler = new CurlHandler();
		$stack = HandlerStack::create($handler);
		
		// Register proxy middleware
		$stack->push($this->_configure_defaults());
		
		self::$_client = new GuzzleHttp\Client(['handler' => $stack]);
		
		return self::$_client;
	}
	
	/**
	 *
	 * @param RequestInterface $request
	 * @param array $options
	 * @param null $error
	 * @param null $error_response
	 * @return ResponseInterfaceAlias|false
	 */
	function sendRequest(RequestInterface $request, array $options=[], &$error=null, &$error_response=null) {
		$client = $this->getClient();
		
		$error = '';
		$error_response = null;
		
		try {
			return $client->send($request, $options);
			
		} catch (RequestException $e) {
			$error = $e->getMessage();
			
			if($e->hasResponse())
				$error_response = $e->getResponse();
			
			return false;
			
		} catch (GuzzleException $e) {
			$error = get_class($e);
			DevblocksPlatform::logException($e);
			return false;
		}
	}
	
	/**
	 * 
	 * @param ResponseInterface $response
	 * @param string $error
	 * @return mixed|false
	 */
	function getResponseAsJson(ResponseInterface $response, &$error=null) {
		$contents = $response->getBody()->getContents();
		
		if(false === ($json = @json_decode($contents, true))) {
			$error = json_last_error();
			return false;
		}
		
		return $json;
	}
	
	public function setHeader(string $name, string $value, $replace=true) : _DevblocksHttpService {
		header(
			sprintf("%s: %s",
				DevblocksPlatform::services()->string()->strStripCrlf($name),
				DevblocksPlatform::services()->string()->strStripCrlf($value)
			),
			$replace
		);
		return $this;
	}
}