<?php
/**
 * Wiaas_Delivery_Process_Step_Test
 *
 * @package Wiaas
 */

class Wiass_REST_Delivery_Process_Api_Test extends Wiaas_Unit_Test_Case {

	var $order_id, $api;

	/**
	 * Test REST Server
	 *
	 * @var WP_REST_Server
	 */
	protected $server;
 
	protected $namespaced_route = '/wiaas';

	function setUp() {
		parent::setUp();

		$order = wc_create_order();

		$this->order_id = $order->get_id();

		wp_set_current_user(1);

		/** @var WP_REST_Server $wp_rest_server */
		global $wp_rest_server;
		$this->server = $wp_rest_server = new \WP_REST_Server;
		do_action( 'rest_api_init' );

		$original_valid_customer_acceptance =  __DIR__ . '/../dummy-files/valid-customer-acceptance.odt';
		$this->test_file_valid_customer_acceptance = '/tmp/valid-customer-acceptance.odt';
		copy( $original_valid_customer_acceptance, $this->test_file_valid_customer_acceptance );

		$original_invalid_customer_acceptance =  __DIR__ . '/../dummy-files/invalid-customer-acceptance.txt';
		$this->test_file_invalid_customer_acceptance = '/tmp/invalid-customer-acceptance.txt';
		copy( $original_invalid_customer_acceptance, $this->test_file_invalid_customer_acceptance );
	}

	function test_register_route() {
		$routes = $this->server->get_routes();
		$this->assertArrayHasKey( $this->namespaced_route, $routes );
	}

 
	function test_endpoints() {
		$the_route = $this->namespaced_route;
		$routes = $this->server->get_routes();
		foreach( $routes as $route => $route_config ) {
			if( 0 === strpos( $the_route, $route ) ) {
				$this->assertTrue( is_array( $route_config ) );
				foreach( $route_config as $i => $endpoint ) {
					$this->assertArrayHasKey( 'callback', $endpoint );
					$this->assertArrayHasKey( 0, $endpoint[ 'callback' ], get_class( $this ) );
					$this->assertArrayHasKey( 1, $endpoint[ 'callback' ], get_class( $this ) );
					$this->assertTrue( is_callable( array( $endpoint[ 'callback' ][0], $endpoint[ 'callback' ][1] ) ) );
				}
			}
		}
	}

	/**
	 * @covers Wiass_REST_Delivery_Process_API::get_next_actions_for_user
	 */
	function test_get_next_actions_for_user() {
		wp_set_current_user(1);

		$response = Wiass_REST_Delivery_Process_API::get_next_actions_for_user();

		$this->assertNotNull($response);
		$this->assertInstanceOf('WP_REST_Response', $response);

		$next_steps = $response->get_data();

		$this->assertNotNull($next_steps);
		$this->assertTrue(is_array($next_steps));

		$pending_step = $next_steps[0];

		$this->assertTrue(is_array($pending_step));

		$this->assertArrayHasKey('order_id', $pending_step);
		$this->assertArrayHasKey('order_number', $pending_step);
		$this->assertArrayHasKey('status', $pending_step);
		$this->assertArrayHasKey('step_action', $pending_step);

		$this->assertEquals($pending_step['order_id'], $this->order_id);
		$this->assertEquals($pending_step['order_number'], $this->order_id);
		$this->assertEquals($pending_step['status'], 'pending');
		$this->assertNotEmpty($pending_step['step_action']);
	}

	/**
	 * @covers Wiass_REST_Delivery_Process_API::get_customer_acceptance
	 */
	function test_get_customer_acceptance_as_guest() {
		wp_set_current_user(0);
		
		$request = new WP_REST_Request( 'GET', '/wiaas/customer-acceptance/99191991919191');
		$response = $this->server->dispatch( $request );

		$this->assertNotNull($response);
		$this->assertInstanceOf('WP_REST_Response',$response);
		$this->assertTrue($response->is_error());
		$this->assertEquals($response->get_status(), 401);

		$error_data = $response->as_error();
		$this->assertEquals($error_data->get_error_message(), 'Sorry, you are not allowed to do that.');
	}

	/**
	 * @covers Wiass_REST_Delivery_Process_API::get_customer_acceptance
	 */
	function test_get_nonexisting_customer_acceptance() {
		wp_set_current_user(1);

		$request = new WP_REST_Request( 'GET', '/wiaas/customer-acceptance/911919191919' ); //non existing entry ID
		$response = $this->server->dispatch( $request );

		$this->assertNotNull($response);
		$this->assertInstanceOf('WP_REST_Response',$response);
		$this->assertTrue($response->is_error());
		$this->assertEquals($response->get_status(), 404);

		$error_data = $response->as_error();
		$this->assertEquals($error_data->get_error_message(), 'Customer acceptance entry not found');
	}

	/**
	 * @covers Wiass_REST_Delivery_Process_API::get_customer_acceptance
	 */
	function test_get_valid_customer_acceptance() {
		wp_set_current_user(1);

		$customer_acceptance_entry_id = self::create_pending_customer_acceptance_entry();
		$request = new WP_REST_Request( 'GET', '/wiaas/customer-acceptance/' . $customer_acceptance_entry_id );
		$response = $this->server->dispatch( $request );

		$this->assertNotNull($response);
		$this->assertInstanceOf('WP_REST_Response',$response);
		$this->assertFalse($response->is_error());
		$this->assertEquals($response->get_status(), 200);

		$response_data = $response->get_data();

		$this->assertTrue(is_array($response_data));
		$this->assertArrayHasKey('documents', $response_data);
		$this->assertArrayHasKey('expiration', $response_data);
		$this->assertArrayHasKey('status', $response_data);
		$this->assertArrayHasKey('decline_reason', $response_data);

		$this->assertTrue(is_array($response_data['documents']));
		$uploaded_file = $response_data['documents'][0];
		$this->assertTrue(is_array($uploaded_file));
		$this->assertArrayHasKey('name', $uploaded_file);
		$this->assertArrayHasKey('extension', $uploaded_file);
		$this->assertArrayHasKey('url', $uploaded_file);
		$this->assertEquals($uploaded_file['name'], 'file1');
		$this->assertEquals($uploaded_file['extension'], 'docx');
		$this->assertEquals($uploaded_file['url'], 'http://localhost/wp/index.php?gf-download=2018%2F08%2Ffile1.docx&form-id=1&field-id=12&hash=1be6c30f0eeff93563b352d15fe459d5ded12ee06c2c8f36fed66b42dedf2534');

		$this->assertEquals($response_data['status'], 1); //1 means accept

		$this->assertEquals($response_data['expiration'], "2020-01-01");
	}

	/**
	 * @covers Wiass_REST_Delivery_Process_API::submit_customer_acceptance
	 */
	function test_submit_customer_acceptance_as_guest() {
		wp_set_current_user(0);

		$request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/9191919191' );
		$response = $this->server->dispatch( $request );

		$this->assertNotNull($response);
		$this->assertInstanceOf('WP_REST_Response',$response);
		$this->assertTrue($response->is_error());
		$this->assertEquals($response->get_status(), 401);

		$error_data = $response->as_error();
		$this->assertEquals($error_data->get_error_message(), 'Sorry, you are not allowed to do that.');
	}

	/**
	 * @covers Wiass_REST_Delivery_Process_API::submit_customer_acceptance
	 */
	function test_submit_nonexisting_customer_acceptance() {
		wp_set_current_user(1);

		$request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/919191919191' );
		$response = $this->server->dispatch( $request );

		$this->assertNotNull($response);
		$this->assertInstanceOf('WP_REST_Response',$response);
		$this->assertTrue($response->is_error());
		$this->assertEquals($response->get_status(), 404);

		$error_data = $response->as_error();
		$this->assertEquals($error_data->get_error_message(), 'Customer acceptance entry not found');
	}

	/**
	 * @covers Wiass_REST_Delivery_Process_API::submit_customer_acceptance
	 */
	function test_submit_customer_acceptance_with_invalid_status() {
		wp_set_current_user(1);

		$customer_acceptance_entry_id = self::create_pending_customer_acceptance_entry();
		$request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/' . $customer_acceptance_entry_id );
		$request->set_body_params(array(
			'actionType' => 'invalid status',
			'declineReason' => ''
		));
		$response = $this->server->dispatch( $request );

		$this->assertNotNull($response);
		$this->assertInstanceOf('WP_REST_Response',$response);
		$this->assertFalse($response->is_error());
		$this->assertEquals($response->get_status(), 200);

		$response_data = $response->get_data();
		$this->assertArrayHasKey('messages', $response_data);
		$this->assertArrayHasKey('data', $response_data);

		$message = $response_data['messages'][0];
		$this->assertArrayHasKey('code', $message);
		$this->assertArrayHasKey('message', $message);
		$this->assertEquals('error', $message['code']);
		$this->assertEquals('ACCEPTANCE_STATUS_MISSING', $message['message']);
	}

	/**
	 * @covers Wiass_REST_Delivery_Process_API::submit_customer_acceptance
	 */
	function test_submit_customer_acceptance_with_accepted_status() {
		wp_set_current_user(1);

		$customer_acceptance_entry_id = self::create_pending_customer_acceptance_entry();
		$request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/' . $customer_acceptance_entry_id );
		$request->set_body_params(array(
			'actionType' => 'accept',
			'declineReason' => ''
		));
		$response = $this->server->dispatch( $request );

		$this->assertNotNull($response);
		$this->assertInstanceOf('WP_REST_Response',$response);
		$this->assertFalse($response->is_error());
		$this->assertEquals($response->get_status(), 200);

		$response_data = $response->get_data();
		$this->assertArrayHasKey('messages', $response_data);
		$this->assertArrayHasKey('data', $response_data);

		$message = $response_data['messages'][0];
		$this->assertArrayHasKey('code', $message);
		$this->assertArrayHasKey('message', $message);
		$this->assertEquals('success', $message['code']);
		$this->assertEquals('INSTALLATION_ACCEPTED', $message['message']);
	}

	/**
	 * @covers Wiass_REST_Delivery_Process_API::submit_customer_acceptance
	 */
	function test_submit_customer_acceptance_with_declined_status_and_empty_reason() {
		wp_set_current_user(1);

		$customer_acceptance_entry_id = self::create_pending_customer_acceptance_entry();
		$request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/' . $customer_acceptance_entry_id );
		$request->set_body_params(array(
			'actionType' => 'decline',
			'declineReason' => ''
		));
		$response = $this->server->dispatch( $request );

		$this->assertNotNull($response);
		$this->assertInstanceOf('WP_REST_Response',$response);
		$this->assertFalse($response->is_error());
		$this->assertEquals($response->get_status(), 200);

		$response_data = $response->get_data();
		$this->assertArrayHasKey('messages', $response_data);
		$this->assertArrayHasKey('data', $response_data);

		$message = $response_data['messages'][0];
		$this->assertArrayHasKey('code', $message);
		$this->assertArrayHasKey('message', $message);
		$this->assertEquals('error', $message['code']);
		$this->assertEquals('DECLINE_REASON_EMPTY', $message['message']);
	}

	/**
	 * @covers Wiass_REST_Delivery_Process_API::submit_customer_acceptance
	 */
	function test_submit_customer_acceptance_with_decline_status() {
		wp_set_current_user(1);

		$customer_acceptance_entry_id = self::create_pending_customer_acceptance_entry();
		$request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/' . $customer_acceptance_entry_id );
		$request->set_body_params(array(
			'actionType' => 'decline',
			'declineReason' => 'This is very reasonable reason'
		));
		$response = $this->server->dispatch( $request );

		$this->assertNotNull($response);
		$this->assertInstanceOf('WP_REST_Response',$response);
		$this->assertFalse($response->is_error());
		$this->assertEquals($response->get_status(), 200);

		$response_data = $response->get_data();
		$this->assertArrayHasKey('messages', $response_data);
		$this->assertArrayHasKey('data', $response_data);

		$message = $response_data['messages'][0];
		$this->assertArrayHasKey('code', $message);
		$this->assertArrayHasKey('message', $message);
		$this->assertEquals('success', $message['code']);
		$this->assertEquals('INSTALLATION_DECLINED', $message['message']);
	}

	/**
	 * @covers Wiass_REST_Delivery_Process_API::upload_file
	 */
	function test_upload_customer_acceptance_file_as_guest() {
		wp_set_current_user(0);

		$request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/919199191/upload-file' );
		$response = $this->server->dispatch( $request );

		$this->assertNotNull($response);
		$this->assertInstanceOf('WP_REST_Response',$response);
		$this->assertTrue($response->is_error());
		$this->assertEquals($response->get_status(), 401);

		$error_data = $response->as_error();
		$this->assertEquals($error_data->get_error_message(), 'Sorry, you are not allowed to do that.');
	}

	/**
	 * @covers Wiass_REST_Delivery_Process_API::upload_file
	 */
	function test_upload_customer_acceptance_file_to_non_existing_entry() {
		wp_set_current_user(1);

		$original_valid_customer_acceptance =  __DIR__ . '/../dummy-files/valid-customer-acceptance.odt';
		$this->test_file_valid_customer_acceptance = '/tmp/valid-customer-acceptance.odt';
		copy( $original_valid_customer_acceptance, $this->test_file_valid_customer_acceptance );
			
		$request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/919199191/upload-file' );
		
		$request->set_file_params( array(
			'file' => array(
				'file'     => file_get_contents( $this->test_file_valid_customer_acceptance ),
				'name'     => 'valid-customer-acceptance.odt',
				'size'     => filesize( $this->test_file_valid_customer_acceptance ),
				'tmp_name' => $this->test_file_valid_customer_acceptance,
			),
		) );
		
		$response = $this->server->dispatch( $request );

		$this->assertNotNull($response);
		$this->assertInstanceOf('WP_REST_Response',$response);
		$this->assertTrue($response->is_error());
		$this->assertEquals($response->get_status(), 404);

		$error_data = $response->as_error();
		$this->assertEquals($error_data->get_error_message(), 'Customer acceptance entry not found');
	}

	/**
	 * @covers Wiass_REST_Delivery_Process_API::upload_file
	 */
	function test_upload_customer_acceptance_file_without_file() {
		wp_set_current_user(1);

		$request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/919199191/upload-file' );
		$response = $this->server->dispatch( $request );

		$this->assertNotNull($response);
		$this->assertInstanceOf('WP_REST_Response',$response);
		$this->assertFalse($response->is_error());
		$this->assertEquals($response->get_status(), 200);

		$response_data = $response->get_data();
		$this->assertArrayHasKey('messages', $response_data);
		$this->assertArrayHasKey('data', $response_data);

		$message = $response_data['messages'][0];
		$this->assertArrayHasKey('code', $message);
		$this->assertArrayHasKey('message', $message);
		$this->assertEquals('error', $message['code']);
		$this->assertEquals('NO_FILES_UPLOADED', $message['message']);
	}

	/**
	 * @covers Wiass_REST_Delivery_Process_API::upload_file
	 */
	function test_upload_invalid_customer_acceptance_file() {
		wp_set_current_user(1);

		$customer_acceptance_entry_id = self::create_pending_customer_acceptance_entry();
		
		$request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/' . $customer_acceptance_entry_id . '/upload-file' );
		$request->set_file_params( array(
			'file' => array(
				'file'     => file_get_contents( $this->test_file_invalid_customer_acceptance ),
				'name'     => 'invalid-customer-acceptance.txt',
				'size'     => filesize( $this->test_file_invalid_customer_acceptance ),
				'tmp_name' => $this->test_file_invalid_customer_acceptance,
			),
		) );
		$request->set_header( 'Content-MD5', md5_file( $this->test_file_invalid_customer_acceptance ) );
		$response = $this->server->dispatch( $request );

		$this->assertNotNull($response);
		$this->assertInstanceOf('WP_REST_Response',$response);
		$this->assertFalse($response->is_error());
		$this->assertEquals($response->get_status(), 200);

		$response_data = $response->get_data();
		$this->assertArrayHasKey('messages', $response_data);
		$this->assertArrayHasKey('data', $response_data);

		$message = $response_data['messages'][0];
		$this->assertArrayHasKey('code', $message);
		$this->assertArrayHasKey('message', $message);
		$this->assertEquals('error', $message['code']);
		$this->assertEquals('INVALID_FILE_ACCEPTANCE', $message['message']);
	}

	/**
	 * @covers Wiass_REST_Delivery_Process_API::upload_file
	 */	
	function test_upload_valid_customer_acceptance_file() {
		wp_set_current_user(1);

		$customer_acceptance_entry_id = self::create_pending_customer_acceptance_entry();
		
		$request = new WP_REST_Request( 'POST', '/wiaas/customer-acceptance/' . $customer_acceptance_entry_id . '/upload-file' );
		$request->set_file_params( array(
			'file' => array(
				'file'     => file_get_contents( $this->test_file_valid_customer_acceptance ),
				'name'     => 'valid-customer-acceptance.odt',
				'size'     => filesize( $this->test_file_valid_customer_acceptance ),
				'tmp_name' => $this->test_file_valid_customer_acceptance,
			),
		) );
		$request->set_header( 'Content-MD5', md5_file( $this->test_file_valid_customer_acceptance ) );
		$response = $this->server->dispatch( $request );

		$this->assertNotNull($response);
		$this->assertInstanceOf('WP_REST_Response',$response);
		$this->assertFalse($response->is_error());
		$this->assertEquals($response->get_status(), 200);

		$response_data = $response->get_data();
		$this->assertArrayHasKey('messages', $response_data);
		$this->assertArrayHasKey('data', $response_data);

		$message = $response_data['messages'][0];
		$this->assertArrayHasKey('code', $message);
		$this->assertArrayHasKey('message', $message);
		$this->assertEquals('success', $message['code']);
		$this->assertEquals('FILE_UPLOADED', $message['message']);
	}

	public function tearDown() {
		parent::tearDown();
		if ( file_exists( $this->test_file_valid_customer_acceptance ) ) {
			unlink( $this->test_file_valid_customer_acceptance );
		}
		if ( file_exists( $this->test_file_invalid_customer_acceptance ) ) {
			unlink( $this->test_file_invalid_customer_acceptance );
		}

		$this->remove_added_uploads();
	}



	//===================================================================================
	/**
	 * Helper function : creates customer acceptance entry
	 */
	private function create_pending_customer_acceptance_entry(){
		$customer_acceptance_form_id = 1;
		
		$customer_id_field_id = 2;
		$actual_date_field_id = 6;
		$acceptance_status_field_id = 8;
		$expiration_date_field_id = 9;
		$decline_reason_field_id = 10;
		$files_uploaded_field_id = 12;
		
		$input_values['input_' . $acceptance_status_field_id] = 'accept';
		$input_values['input_' . $expiration_date_field_id] = "2020-01-01";
		//$input_values['input_' . $files_uploaded_field_id] = json_encode(['http://path/to/file1.docx']);
		
		GFAPI::submit_form($customer_acceptance_form_id, $input_values);
		
		//this part is needed since form submit does not store files for some reason, probably files should be sent some other way
		$entry = GFAPI::get_entries($customer_acceptance_form_id)[0];
		$entry[$files_uploaded_field_id] = json_encode(['http://localhost/wp/index.php?gf-download=2018%2F08%2Ffile1.docx&form-id=1&field-id=12&hash=1be6c30f0eeff93563b352d15fe459d5ded12ee06c2c8f36fed66b42dedf2534']);
		$entry['workflow_step'] = 1; 
		$entry['workflow_step_status_1'] = 'pending';
		$entry['workflow_step_status_2'] = false;
		$entry['workflow_timestamp'] = false;
		$update = GFAPI::update_entry($entry);

		return $entry['id'];
	}


}
