<?php

declare(strict_types=1);

namespace ComerciaGlobalPayments\AddonPayments\SDK\Api;

use ComerciaGlobalPayments\AddonPayments\SDK\Request as _Request;
use ComerciaGlobalPayments\AddonPayments\SDK\Response as _Response;
use ComerciaGlobalPayments\AddonPayments\SDK\Response\ResponseInterface;
use GuzzleHttp\Exception\TransferException;

/**
 * Implements client for the EPGJS API.
 *
 * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
 * @SuppressWarnings(PHPMD.StaticAccess)
 */
class EPGJs extends AbstractApiClient
{
    public const NAME = 'EPGJs';

    public const EPGJS_STYLE_DEFAULT = 'DEFAULT_THEME';

    public const EPGJS_STYLE_BOOTSTRAP = 'DEFAULT_BOOTSTRAP_THEME';

    /**
     * Send authorization request.
     */
    public function authorization(_Request\Authorization $request): ResponseInterface
    {
        $request
            ->setMerchantId((string) $this->configuration['merchantId'])
            ->setMerchantKey((string) $this->configuration['merchantKey']);
        $this->doValidate($request, __FUNCTION__);
        try {
            $payload = $request->jsonSerialize();
            $request
                ->addHeader('Content-Type', 'application/json; charset=UTF-8')
                ->addHeader('Accept', 'application/json')
                ->addHeader('apiVersion', '3');

            /** @var \GuzzleHttp\Message\ResponseInterface|\Psr\Http\Message\ResponseInterface $response */
            $response = $this->sendRequest(
                'post',
                $this->getEndpoint(__FUNCTION__),
                $request->getAdditionalHeaders(),
                $payload
            );

            return new _Response\Authorized($response);
        } catch (TransferException $e) {
            return $this->handleApiException($e);
        }
    }

    /**
     * Send charge request.
     */
    public function charge(_Request\Charge $request): ResponseInterface
    {
        $request
            ->setMerchantId((string) $this->configuration['merchantId'])
            ->settle();

        return $this->doCharge(__FUNCTION__, $request);
    }

    /**
     * Send pre-authorization request.
     */
    public function preAuth(_Request\Charge $request): ResponseInterface
    {
        $request
            ->setMerchantId((string) $this->configuration['merchantId'])
            ->preAuthorize();

        return $this->doCharge(__FUNCTION__, $request);
    }

    /**
     * Perform the actual charge request.
     */
    private function doCharge(string $operation, _Request\Charge $request)
    {
        $this->doValidate($request, $operation);
        try {
            $payload = $request->jsonSerialize();
            $request
                ->addHeader('Content-Type', 'application/json; charset=UTF-8')
                ->addHeader('Accept', 'application/json')
                ->addHeader('apiVersion', '3');
            $response = $this->sendRequest(
                'post',
                $this->getEndpoint($operation),
                $request->getAdditionalHeaders(),
                $payload
            );

            return new _Response\Operation($response);
        } catch (TransferException $e) {
            return $this->handleApiException($e);
        }
    }

    /**
     * Send void request.
     */
    public function voided(_Request\Voided $request): ResponseInterface
    {
        $request->setMerchantId((string) $this->configuration['merchantId']);

        return $this->doEncryptedRequest(__FUNCTION__, $request, $this->configuration['merchantSecret']);
    }

    /**
     * Send capture request.
     */
    public function capture(_Request\Capture $request): ResponseInterface
    {
        $request->setMerchantId((string) $this->configuration['merchantId']);

        return $this->doEncryptedRequest(__FUNCTION__, $request, $this->configuration['merchantSecret']);
    }

    /**
     * Send refund request.
     */
    public function refund(_Request\Refund $request): ResponseInterface
    {
        $request->setMerchantId((string) $this->configuration['merchantId']);

        return $this->doEncryptedRequest(__FUNCTION__, $request, $this->configuration['merchantSecret']);
    }

    /**
     * Send a request to query status of given transactions.
     */
    public function transactions(_Request\Transactions $request): ResponseInterface
    {
        $request->setMerchantId((string) $this->configuration['merchantId']);
        $request->setToken($this->generateTransactionToken($request->getTransactions()));

        return $this->doEncryptedRequest(__FUNCTION__, $request, $this->configuration['merchantSecret']);
    }

    /**
     * Send a request to query status of transaction on a given date range.
     */
    public function transactionsByDate(_Request\TransactionsByDate $request): ResponseInterface
    {
        $request->setMerchantId((string) $this->configuration['merchantId']);

        return $this->doEncryptedRequest(__FUNCTION__, $request, $this->configuration['merchantSecret']);
    }

    /**
     * Perform encrypted requests main logic.
     */
    private function doEncryptedRequest(string $operation, _Request\AbstractEncryptedRequest $request, string $key): ResponseInterface
    {
        $this->doValidate($request, $operation);
        try {
            $encryptedPayload = $request
                ->encrypt($this->getEncryption(), $key)
                ->getPayload();
            $request
                ->addHeader('Content-Type', 'text/plain; charset=UTF-8')
                ->addHeader('Accept', 'application/json')
                ->addHeader('apiVersion', '3');

            $endpoint = $this->getEndpoint($operation);
            $parameters = http_build_query($encryptedPayload);
            $response = $this->sendRequest(
                'post',
                "$endpoint?$parameters",
                $request->getAdditionalHeaders()
            );

            return new _Response\Operation($response);
        } catch (TransferException $e) {
            return $this->handleApiException($e);
        }
    }

    /**
     * Send a request to disable a registered account.
     *
     * @todo Refactor to return the full response of the service instead of just OK/KO flag.
     */
    public function accountDisable(_Request\AccountDisable $request): bool
    {
        $this->doValidate($request, __FUNCTION__);
        try {
            $endpoint = $this->getEndpoint(__FUNCTION__);
            $endpoint = str_replace('{accountId}', $request->getAccountId(), $endpoint);
            $request->addHeader('Accept', 'application/json');
            $this->sendRequest(
                'post',
                $endpoint,
                $request->getAdditionalHeaders()
            );

            return true;
        } catch (TransferException $e) {
            return false;
        }
    }

    public function expressCheckout(_Request\ExpressCheckout $request): ResponseInterface
    {
        $request->setMerchantId((string) $this->configuration['merchantId']);
        $this->doValidate($request, __FUNCTION__);
        try {
            $endpoint = $this->getEndpoint(__FUNCTION__);
            $request->addHeader('Accept', 'application/json');
            $parameters = http_build_query($request->jsonSerialize());
            $response = $this->sendRequest(
                'post',
                "$endpoint?$parameters",
                $request->getAdditionalHeaders()
            );

            return new _Response\ExpressCheckout($response);
        } catch (TransferException $e) {
            return $this->handleApiException($e);
        }
    }

    public static function getEndpoints(bool $live = false): array
    {
        $stagingEndpoints = [
            'base' => 'https://epgjs-web-stg.easypaymentgateway.com/',
            'redirect' => 'https://checkout-stg.easypaymentgateway.com/EPGCheckout',
            'render' => 'https://epgjs-rendercashier-stg.easypaymentgateway.com/js/public/epgjs-4.0.0-min.js',
            'render-css' => 'https://epgjs-rendercashier-stg.easypaymentgateway.com/css/platform.css',
            'nemuru-widget' => 'https://epgjs-rendercashier-stg.easypaymentgateway.com/js/paysol-js/quix/nemuru-widget-module.js',
            'authorization' => 'https://epgjs-mep-stg.easypaymentgateway.com/auth',
            'charge' => 'https://epgjs-mep-stg.easypaymentgateway.com/charge',
            'preAuth' => 'https://epgjs-mep-stg.easypaymentgateway.com/charge',
            'voided' => 'https://checkout-stg.easypaymentgateway.com/EPGCheckout/rest/online/void',
            'capture' => 'https://checkout-stg.easypaymentgateway.com/EPGCheckout/rest/online/capture',
            'refund' => 'https://checkout-stg.easypaymentgateway.com/EPGCheckout/rest/online/rebate',
            'transactions' => 'https://checkout-stg.easypaymentgateway.com/EPGCheckout/rest/online/merchantcall/repeat',
            'transactionsByDate' => 'https://checkout-stg.easypaymentgateway.com/EPGCheckout/rest/online/statusByDate',
            'accountDisable' => 'https://epgjs-web-stg.easypaymentgateway.com/account/disable/{accountId}',
            'expressCheckout' => 'https://checkout-stg.easypaymentgateway.com/EPGCheckout/rest/online/epgExpressCheckout',
        ];
        $liveEndpoints = [
            'base' => 'https://epgjs-web.easypaymentgateway.com/',
            'redirect' => 'https://checkout.easypaymentgateway.com/EPGCheckout',
            'render' => 'https://epgjs-rendercashier.easypaymentgateway.com/js/public/epgjs-4.0.0-min.js',
            'render-css' => 'https://epgjs-rendercashier.easypaymentgateway.com/css/platform.css',
            'nemuru-widget' => 'https://epgjs-rendercashier.easypaymentgateway.com/js/paysol-js/quix/nemuru-widget-module.js',
            'authorization' => 'https://epgjs-mep.easypaymentgateway.com/auth',
            'charge' => 'https://epgjs-mep.easypaymentgateway.com/charge',
            'preAuth' => 'https://epgjs-mep.easypaymentgateway.com/charge',
            'voided' => 'https://checkout.easypaymentgateway.com/EPGCheckout/rest/online/void',
            'capture' => 'https://checkout.easypaymentgateway.com/EPGCheckout/rest/online/capture',
            'refund' => 'https://checkout.easypaymentgateway.com/EPGCheckout/rest/online/rebate',
            'transactions' => 'https://checkout.easypaymentgateway.com/EPGCheckout/rest/online/merchantcall/repeat',
            'transactionsByDate' => 'https://checkout.easypaymentgateway.com/EPGCheckout/rest/online/statusByDate',
            'accountDisable' => 'https://epgjs-web.easypaymentgateway.com/account/disable/{accountId}',
            'expressCheckout' => 'https://checkout.easypaymentgateway.com/EPGCheckout/rest/online/epgExpressCheckout',
        ];

        if ($live) {
            return $liveEndpoints;
        }

        return $stagingEndpoints;
    }
}
