<?php

namespace PHPOnCouch\Adapter;

use InvalidArgumentException,
	PHPOnCouch\Exceptions,
	PHPOnCouch\CouchClient,
	PHPUnit_Framework_TestCase,
	stdClass;

require_once join(DIRECTORY_SEPARATOR, [dirname(__DIR__), '_config', 'config.php']);

/**
 * Generated by PHPUnit_SkeletonGenerator on 2016-11-01 at 15:39:08.
 * @backupGlobals disabled
 * @backupStaticAttributes disabled
 */
class CouchHttpAdapterCurlTest extends PHPUnit_Framework_TestCase
{

	private $host = 'localhost';
	private $port = '5984';
	private $admin = ["login" => "adm", "password" => "sometest"];
	protected $adapter;

	/**
	 *
	 * @var PHPOnCouch\CouchClient
	 */
	private $client;

	/**
	 *
	 * @var PHPOnCouch\CouchClient
	 */
	private $aclient;

	/**
	 * Sets up the fixture, for example, opens a network connection.
	 * This method is called before a test is executed.
	 */
	protected function setUp()
	{
		$config = \config::getInstance();
		$this->host = $config->getHost();
		$this->port = $config->getPort();
//        $url = $config->getUrl($this->host, $this->port, null);
		$aUrl = $config->getUrl($this->host, $this->port, $config->getFirstAdmin());
		$this->dbname = 'couchclienttest';
		$this->aclient = new CouchClient($aUrl, $this->dbname);
//        $this->aclient = new CouchClient($aUrl, 'couchclienttest');
		try {
			$this->aclient->deleteDatabase();
		} catch (\Exception $e) {
			
		}
		$this->aclient->createDatabase();
		$this->adapter = new \PHPOnCouch\Adapter\CouchHttpAdapterCurl("localhost", []);
		$this->adapter->setDsn($this->aclient->dsn());
	}

	/**
	 * Tears down the fixture, for example, closes a network connection.
	 * This method is called after a test is executed.
	 */
	protected function tearDown()
	{
//        $this->client = null;
		$this->aclient = null;
		$this->adapter = null;
	}

	private function addDefaultDoc()
	{
		$docId = 'default_doc';
		$this->aclient->storeDoc((object) ['_id' => $docId, 'name' => 'Default document']);
		return $docId;
	}

	public function testCustomCurlOptions()
	{
		$adapter = $this->adapter;
		$adapterOptions = ['curl' => [CURLOPT_URL => 'http://www.example.com/']];
		$addCustomOptions = new \ReflectionMethod($adapter, 'addCustomOptions');
		$addCustomOptions->setAccessible(true);
		$curlHandle = curl_init();
		$adapter->setOptions($adapterOptions);
		$addCustomOptions->invoke($adapter, $curlHandle);
		$info = curl_getinfo($curlHandle);
		$this->assertEquals($adapterOptions['curl'][CURLOPT_URL], $info['url']);
	}

	public function testBuildRequestSendCookie()
	{
		//Add document for the copy function
		$id = $this->addDefaultDoc();

		$sessionCookie = "foo=bar";
		$adapter = $this->adapter;
		$adapter->setSessionCookie($sessionCookie);
		$this->assertTrue($adapter->hasSessionCookie());
		$this->assertEquals($sessionCookie, $adapter->getSessionCookie());
		$buildRequest = new \ReflectionMethod($adapter, 'buildRequest');
		$buildRequest->setAccessible(true);
		$curlHandle = $buildRequest->invokeArgs($adapter, [
			'COPY',
			$this->aclient->getDatabaseUri() . "/$id",
			"new_doc",
			null
		]);
		curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($curlHandle, CURLOPT_VERBOSE, true);
		curl_setopt($curlHandle, CURLINFO_HEADER_OUT, true);
		curl_exec($curlHandle);
		$header = curl_getinfo($curlHandle);
		$httpReq = $header['request_header'];

		$this->assertNotFalse(strpos($httpReq, "Cookie: $sessionCookie"));
		$this->assertNotFalse(strpos($httpReq, "Cookie: " . $adapter->getSessionCookie()));
	}

	public function testBuildRequestSendCustomContentType()
	{
		//Add document for the copy function
		$id = $this->addDefaultDoc();
		$contentType = "foo/bar";
		$data = ['foo' => 'bar'];
		$adapter = $this->adapter;
		$buildRequest = new \ReflectionMethod($adapter, 'buildRequest');
		$buildRequest->setAccessible(true);
		$curlHandle = $buildRequest->invokeArgs($adapter, [
			'COPY',
			$this->aclient->getDatabaseUri() . "/$id",
			$data,
			$contentType
		]);
		curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($curlHandle, CURLINFO_HEADER_OUT, true);
		curl_exec($curlHandle);
		$header = curl_getinfo($curlHandle);
		$httpReq = $header['request_header'];
		$this->assertNotFalse(strpos($httpReq, "Destination: " . json_encode($data)));
	}

	public function testBuildRequestSendDefaultContentType()
	{
		//Add document for the copy function
		$id = $this->addDefaultDoc();
		$defaultContentType = "application/json";
		$adapter = $this->adapter;
		$buildRequest = new \ReflectionMethod($adapter, 'buildRequest');
		$buildRequest->setAccessible(true);
		$curlHandle = $buildRequest->invokeArgs($adapter, [
			'COPY',
			$this->aclient->getDatabaseUri() . "/$id",
			['foo' => 'bar'],
			null
		]);
		curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($curlHandle, CURLINFO_HEADER_OUT, true);
		curl_exec($curlHandle);
		$header = curl_getinfo($curlHandle);
		$httpReq = $header['request_header'];
		$this->assertNotFalse(strpos($httpReq, 'application/json'));
	}

	public function testQuery()
	{
		$response = $this->adapter->query('GET', '/' . $this->dbname . "/_all_docs?limit=5");
		$parsedResponse = \PhpOnCouch\Couch::parseRawResponse($response);
		$this->assertArrayHasKey('status_code', $parsedResponse);
		$this->assertArrayHasKey('status_message', $parsedResponse);
		$this->assertEquals('200', $parsedResponse['status_code']);
		$this->assertEquals('OK', $parsedResponse['status_message']);

		$this->expectException("\Exception");
		$this->adapter->query("NOEXISTING", "something");
	}

	public function testStoreFile()
	{
		$doc = (object) ['_id' => 'test_store_as_file'];

		$file = join(DIRECTORY_SEPARATOR, [dirname(__DIR__), '_config', 'test.txt']);
		$filename = 'GoogleHomepage.html';
		$contentType = 'text/html';

		$url = '/' . $this->dbname . '/' . urlencode($doc->_id) . '/' . urlencode($filename);

		$rawResponse = $this->adapter->storeFile($url, $file, $contentType);
		$parsedResponse = \PhpOnCouch\Couch::parseRawResponse($rawResponse);
		$this->assertArrayHasKey('status_code', $parsedResponse);
		$this->assertArrayHasKey('status_message', $parsedResponse);
		$this->assertEquals('201', $parsedResponse['status_code']);
		$this->assertEquals('Created', $parsedResponse['status_message']);

		$this->expectException("\Exception");
		$this->adapter->storeFile("NOEXISTING", "something", "");
	}

	public function testStoreAsFile()
	{
		$doc = (object) ['_id' => 'test_store_as_file'];

		$data = file_get_contents('http://www.google.com/');
		$filename = 'GoogleHomepage.html';
		$contentType = 'text/html';

		$url = '/' . $this->dbname . '/' . urlencode($doc->_id) . '/' . urlencode($filename);

		$rawResponse = $this->adapter->storeAsFile($url, $data, $contentType);
		$parsedResponse = \PhpOnCouch\Couch::parseRawResponse($rawResponse);
		$this->assertArrayHasKey('status_code', $parsedResponse);
		$this->assertArrayHasKey('status_message', $parsedResponse);
		$this->assertEquals('201', $parsedResponse['status_code']);
		$this->assertEquals('Created', $parsedResponse['status_message']);

		$this->expectException("\Exception");
		$this->adapter->storeAsFile("NOEXISTING", "something", "");
	}


    public function testInitSocketAdapter(){
        $adapter = $this->adapter;
        $options = ['test'=> true];
        $cookie = "AuthSession=laksdlaksldkasldkalskd";

        $adapter->setOptions($options);
        $adapter->setSessionCookie($cookie);

        $initSocketAdapter = new \ReflectionMethod($adapter, 'initSocketAdapter');
        $initSocketAdapter->setAccessible(true);
        $initSocketAdapter->invokeArgs($adapter,[]);

        $reflectedAdapter = new \ReflectionClass(CouchHttpAdapterCurl::class);
        $socketAdapterProp = $reflectedAdapter->getProperty('socketAdapter');
        $socketAdapterProp->setAccessible(true);
        $socketAdapter = $socketAdapterProp->getValue($adapter);

        $this->assertEquals($cookie,$socketAdapter->getSessionCookie());
        $this->assertEquals($options,$socketAdapter->getOptions());
    }

	public function testSetCookie(){
        $adapter = $this->adapter;
        $cookie = "AuthSession=laksdlaksldkasldkalskd";

        $initSocketAdapter = new \ReflectionMethod($adapter, 'initSocketAdapter');
        $initSocketAdapter->setAccessible(true);
        $initSocketAdapter->invokeArgs($adapter,[]);

        $adapter->setSessionCookie($cookie);

        $reflectedAdapter = new \ReflectionClass(CouchHttpAdapterCurl::class);
        $socketAdapterProp = $reflectedAdapter->getProperty('socketAdapter');
        $socketAdapterProp->setAccessible(true);
        $socketAdapter = $socketAdapterProp->getValue($adapter);

        $this->assertEquals($cookie,$socketAdapter->getSessionCookie());
    }

    public function testSetOptions(){
        $adapter = $this->adapter;
        $options = ['test'=> true];

        $initSocketAdapter = new \ReflectionMethod($adapter, 'initSocketAdapter');
        $initSocketAdapter->setAccessible(true);
        $initSocketAdapter->invokeArgs($adapter,[]);

        $adapter->setOptions($options);

        $reflectedAdapter = new \ReflectionClass(CouchHttpAdapterCurl::class);
        $socketAdapterProp = $reflectedAdapter->getProperty('socketAdapter');
        $socketAdapterProp->setAccessible(true);
        $socketAdapter = $socketAdapterProp->getValue($adapter);

        $this->assertEquals($options,$socketAdapter->getOptions());
    }


}
