<?php

namespace PayPal\Test\Functional\Api;

use PayPal\Api\Patch;
use PayPal\Api\PatchRequest;
use PayPal\Api\Webhook;
use PayPal\Api\WebhookEvent;
use PayPal\Api\WebhookEventType;
use PayPal\Api\WebhookEventTypeList;
use PayPal\Api\WebhookList;
use PayPal\Exception\PayPalConnectionException;
use PayPal\Test\Functional\Setup;
use PHPUnit\Framework\TestCase;

/**
 * Class WebhookFunctionalTest
 *
 * @package PayPal\Test\Api
 */
class WebhookFunctionalTest extends TestCase
{

    public $operation;

    public $response;

    public $mockPayPalRestCall;

    public $apiContext;

    public function setUp()
    {
        $className = $this->getClassName();
        $testName = $this->getName();
        $operationString = file_get_contents(__DIR__ . "/../resources/$className/$testName.json");
        $this->operation = json_decode($operationString, true);
        $this->response = true;
        if (array_key_exists('body', $this->operation['response'])) {
            $this->response = json_encode($this->operation['response']['body']);
        }
        Setup::SetUpForFunctionalTests($this);
    }

    /**
     * Returns just the classname of the test you are executing. It removes the namespaces.
     * @return string
     */
    public function getClassName()
    {
        return join('', array_slice(explode('\\', get_class($this)), -1));
    }

    public function testCreate()
    {
        $request = $this->operation['request']['body'];
        $obj = new Webhook($request);
        // Adding a random url request to make it unique
        $obj->setUrl($obj->getUrl() . '?rand=' . uniqid());
        $result = null;
        try {
            $result = $obj->create($this->apiContext, $this->mockPayPalRestCall);
        } catch (PayPalConnectionException $ex) {
            $data = $ex->getData();
            if (strpos($data, 'WEBHOOK_NUMBER_LIMIT_EXCEEDED') !== false) {
                $this->deleteAll();
                $result = $obj->create($this->apiContext, $this->mockPayPalRestCall);
            } else {
                $this->fail($ex->getMessage());
            }
        }
        $this->assertNotNull($result);
        return $result;
    }

    public function deleteAll()
    {
        $result = Webhook::getAll($this->apiContext, $this->mockPayPalRestCall);
        foreach ($result->getWebhooks() as $webhookObject) {
            $webhookObject->delete($this->apiContext, $this->mockPayPalRestCall);
        }
    }

    /**
     * @depends testCreate
     * @param $webhook Webhook
     * @return Webhook
     */
    public function testGet($webhook)
    {
        $result = Webhook::get($webhook->getId(), $this->apiContext, $this->mockPayPalRestCall);
        $this->assertNotNull($result);
        $this->assertEquals($webhook->getId(), $result->getId());
        return $result;
    }

    /**
     * @depends testGet
     * @param $webhook Webhook
     * @return WebhookEventTypeList
     */
    public function testGetSubscribedEventTypes($webhook)
    {
        $result = WebhookEventType::subscribedEventTypes($webhook->getId(), $this->apiContext, $this->mockPayPalRestCall);
        $this->assertNotNull($result);
        $this->assertCount(2, $result->getEventTypes());
        return $result;
    }

    /**
     * @depends testGet
     * @param $webhook Webhook
     * @return WebhookList
     */
    public function testGetAll($webhook)
    {
        $result = Webhook::getAll($this->apiContext, $this->mockPayPalRestCall);
        $this->assertNotNull($result);
        $found = false;
        $foundObject = null;
        foreach ($result->getWebhooks() as $webhookObject) {
            if ($webhookObject->getId() == $webhook->getId()) {
                $found = true;
                $foundObject = $webhookObject;
                break;
            }
        }
        $this->assertTrue($found, "The Created Webhook was not found in the get list");
        $this->assertEquals($webhook->getId(), $foundObject->getId());
        return $result;
    }

    /**
     * @depends testGet
     * @param $webhook Webhook
     */
    public function testUpdate($webhook)
    {
        $patches = array();
        foreach ($this->operation['request']['body'] as $request) {
            /** @var Patch[] $request */
            $patch = new Patch();
            $patch->setOp($request['op']);
            $patch->setPath($request['path']);
            $patch->setValue($request['value']);
            if ($request['path'] == "/url") {
                $new_url = $request['value'] . '?rand=' .uniqid();
                $patch->setValue($new_url);
            }
            $patches[] = $patch;
        }

        $patchRequest = new PatchRequest();
        $patchRequest->setPatches($patches);
        $result = $webhook->update($patchRequest, $this->apiContext, $this->mockPayPalRestCall);
        $this->assertNotNull($result);
        $found = false;
        $foundObject = null;
        foreach ($result->getEventTypes() as $eventType) {
            if ($eventType->getName() == "PAYMENT.SALE.REFUNDED") {
                $found = true;
                break;
            }
        }
        $this->assertTrue($found);
    }

    /**
     * @depends testGet
     * @param $webhook Webhook
     */
    public function testDelete($webhook)
    {
        $result = $webhook->delete($this->apiContext, $this->mockPayPalRestCall);
        $this->assertTrue($result);
    }

    public function testEventSearch()
    {
        $result = WebhookEvent::all(array(), $this->apiContext, $this->mockPayPalRestCall);
        $this->assertNotNull($result);
        return $result;
    }
}
