<?php

declare(strict_types=1);

namespace ComerciaGlobalPayments\Tests\AddonPayments\SDK\Api\Unit\EPGJs;

use ComerciaGlobalPayments\AddonPayments\SDK\Api\EPGJs;
use ComerciaGlobalPayments\AddonPayments\SDK\Encryption\Cypher\Aes256Ecb;
use ComerciaGlobalPayments\AddonPayments\SDK\Request\Refund;
use ComerciaGlobalPayments\AddonPayments\SDK\Response\ErrorResponse;
use ComerciaGlobalPayments\AddonPayments\SDK\Response\Operation;
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;

/**
 * Tests refund through EPGJs API client.
 *
 * @coversDefaultClass \ComerciaGlobalPayments\AddonPayments\SDK\Api\EPGJs
 * @covers \ComerciaGlobalPayments\AddonPayments\SDK\Request\Refund
 * @covers \ComerciaGlobalPayments\AddonPayments\SDK\Response\Operation
 * @covers \ComerciaGlobalPayments\AddonPayments\SDK\Response\Transaction
 * @covers \ComerciaGlobalPayments\AddonPayments\SDK\Request\AbstractEncryptedRequest
 *
 * @uses   \ComerciaGlobalPayments\AddonPayments\SDK\Api\AbstractApiClient
 * @uses   \ComerciaGlobalPayments\AddonPayments\SDK\Encryption\JWT\PrivatePublicKeysEncoder
 * @uses   \ComerciaGlobalPayments\AddonPayments\SDK\Encryption\Cypher\Aes256Cbc
 * @uses   \ComerciaGlobalPayments\AddonPayments\SDK\Encryption\Cypher\Aes256Ecb
 * @uses   \ComerciaGlobalPayments\AddonPayments\SDK\Response\ErrorResponse
 * @uses   \ComerciaGlobalPayments\AddonPayments\SDK\Request\AbstractRequest
 *
 * @SuppressWarnings(PHPMD.StaticAccess)
 * @SuppressWarnings(PHPMD.LongVariableNames)
 */
class RefundTest extends EPGJsTestBase
{
    /**
     * @covers       ::refund
     * @covers       ::doEncryptedRequest
     * @covers       ::getEndpoints
     * @covers       \ComerciaGlobalPayments\AddonPayments\SDK\Request\AbstractRequest
     * @covers       \ComerciaGlobalPayments\AddonPayments\SDK\Request\AbstractMITRequest
     * @covers       \ComerciaGlobalPayments\AddonPayments\SDK\Request\Refund
     * @covers       \ComerciaGlobalPayments\AddonPayments\SDK\Response\AbstractResponse
     * @covers       \ComerciaGlobalPayments\AddonPayments\SDK\Response\Operation
     * @covers       \ComerciaGlobalPayments\AddonPayments\SDK\Response\Transaction
     */
    public function testRefundWithCbc(): void
    {
        $mockHandler = new MockHandler(
            [[$this, 'encryptedResponseHandler']]
        );

        $handler = HandlerStack::create($mockHandler);
        $httpClient = new Client(['handler' => $handler, 'delay' => random_int(1, 60)]);
        $this->apiClient = new EPGJs($this->apiClientConfig, $httpClient);
        $request = (new Refund())
            ->setMerchantTransactionId(uniqid())
            ->setAmount(round(random_int(1, 50) * \M_PI, 6))
            ->setPaymentSolution('Paypal')
            ->setTransactionId(uniqid())
            ->setDescription('Test refund operation')
            ->setMerchantParams(['test' => base64_encode(__CLASS__)]);
        /** @var \ComerciaGlobalPayments\AddonPayments\SDK\Response\Operation $response */
        $response = $this->apiClient->refund($request);
        self::assertInstanceOf(
            Operation::class,
            $response,
            'Test the API response is OK'
        );
        self::assertNotEmpty(
            $response->getOperations(),
            'Test the API response returns one or more transactions'
        );
        self::assertNotEmpty(
            $response->getHttpResponse(),
            'Test the API response wraps the actual HTTP response'
        );
    }

    /**
     * @covers       ::refund
     * @covers       ::doEncryptedRequest
     * @covers       ::getEndpoints
     * @covers       \ComerciaGlobalPayments\AddonPayments\SDK\Request\AbstractRequest
     * @covers       \ComerciaGlobalPayments\AddonPayments\SDK\Request\AbstractMITRequest
     * @covers       \ComerciaGlobalPayments\AddonPayments\SDK\Request\Refund
     * @covers       \ComerciaGlobalPayments\AddonPayments\SDK\Response\AbstractResponse
     * @covers       \ComerciaGlobalPayments\AddonPayments\SDK\Response\Operation
     * @covers       \ComerciaGlobalPayments\AddonPayments\SDK\Response\Transaction
     */
    public function testRefundWithEcb(): void
    {
        $mockHandler = new MockHandler(
            [[$this, 'encryptedResponseHandler']]
        );

        $handler = HandlerStack::create($mockHandler);
        $httpClient = new Client(['handler' => $handler, 'delay' => random_int(1, 60)]);
        $config = $this->apiClientConfig;
        $config['encryption'] = Aes256Ecb::NAME;
        $this->apiClient = new EPGJs($config, $httpClient);
        $request = (new Refund())
            ->setMerchantTransactionId(uniqid())
            ->setAmount(round(random_int(1, 50) * \M_PI, 6))
            ->setPaymentSolution('Paypal')
            ->setTransactionId(uniqid())
            ->setDescription('Test refund operation')
            ->setMerchantParams(['test' => base64_encode(__CLASS__)]);
        /** @var \ComerciaGlobalPayments\AddonPayments\SDK\Response\Operation $response */
        $response = $this->apiClient->refund($request);
        self::assertInstanceOf(
            Operation::class,
            $response,
            'Test the API response is OK'
        );
        self::assertNotEmpty(
            $response->getOperations(),
            'Test the API response returns one or more transactions'
        );
        self::assertNotEmpty(
            $response->getHttpResponse(),
            'Test the API response wraps the actual HTTP response'
        );
    }

    /**
     * @covers       ::refund
     * @covers       ::doEncryptedRequest
     * @covers       ::getEndpoints
     * @covers       \ComerciaGlobalPayments\AddonPayments\SDK\Request\AbstractRequest
     * @covers       \ComerciaGlobalPayments\AddonPayments\SDK\Request\AbstractMITRequest
     * @covers       \ComerciaGlobalPayments\AddonPayments\SDK\Request\Refund
     * @covers       \ComerciaGlobalPayments\AddonPayments\SDK\Response\AbstractResponse
     * @covers       \ComerciaGlobalPayments\AddonPayments\SDK\Response\Operation
     * @covers       \ComerciaGlobalPayments\AddonPayments\SDK\Response\Transaction
     */
    public function testFailedRefund(): void
    {
        $mockHandler = new MockHandler(
            [[$this, 'encryptedResponseHandler']]
        );

        $handler = HandlerStack::create($mockHandler);
        $httpClient = new Client(['handler' => $handler, 'delay' => random_int(1, 60)]);
        $expectToFail = 0 === (random_int(2, 5) % 2);
        $this->apiClient = new EPGJs($this->apiClientConfig, $httpClient);
        /** @var \ComerciaGlobalPayments\AddonPayments\SDK\Request\Refund $request */
        $request = (new Refund())
            ->setMerchantTransactionId(uniqid())
            ->setAmount(round(random_int(1, 50) * \M_PI, 6))
            ->setPaymentSolution('Paypal')
            ->setTransactionId(uniqid())
            ->setDescription('Test refund operation')
            ->setMerchantParams(['test' => base64_encode(__CLASS__)])
            ->addHeader(self::EXPECTED_TO_FAIL_HEADER, $expectToFail ? 'true' : 'false');
        /** @var \ComerciaGlobalPayments\AddonPayments\SDK\Response\ErrorResponse|\ComerciaGlobalPayments\AddonPayments\SDK\Response\Operation $response */
        $response = $this->apiClient->refund($request);
        if ($expectToFail) {
            self::assertInstanceOf(
                ErrorResponse::class,
                $response,
                'Test the API response is KO'
            );
            self::assertNotEmpty(
                $response->getHttpResponse(),
                'Test the API error response wraps the actual HTTP response'
            );

            return;
        }

        self::assertInstanceOf(
            Operation::class,
            $response,
            'Test the API response is OK'
        );
    }
}
