<?php

namespace PayPal\Api;

use PayPal\Common\PayPalResourceModel;
use PayPal\Core\PayPalConstants;
use PayPal\Rest\ApiContext;
use PayPal\Transport\PayPalRestCall;
use PayPal\Validation\ArgumentValidator;

/**
 * Class Payment
 *
 * Lets you create, process and manage payments.
 *
 * @package PayPal\Api
 *
 * @property string                              id
 * @property string                              intent
 * @property \PayPal\Api\Payer                   payer
 * @property \PayPal\Api\PotentialPayerInfo      potential_payer_info
 * @property \PayPal\Api\Payee                   payee
 * @property \PayPal\Api\Transaction[]           transactions
 * @property string[] billing_agreement_tokens
 * @property \PayPal\Api\PaymentInstruction      payment_instruction
 * @property string                              state
 * @property string                              experience_profile_id
 * @property string                              note_to_payer
 * @property \PayPal\Api\RedirectUrls            redirect_urls
 * @property string                              failure_reason
 * @property string                              create_time
 * @property string                              update_time
 * @property \PayPal\Api\Links[]                 links
 */
class Payment extends PayPalResourceModel
{
    /**
     * ID of the created payment, the 'transaction ID'
     *
     * @param string $id
     *
     * @return $this
     */
    public function setId($id)
    {
        $this->id = $id;
        return $this;
    }

    /**
     * ID of the created payment, the 'transaction ID'
     *
     * @return string
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Payment intent.
     * Valid Values: ["sale", "authorize", "order"]
     *
     * @param string $intent
     *
     * @return $this
     */
    public function setIntent($intent)
    {
        $this->intent = $intent;
        return $this;
    }

    /**
     * Payment intent.
     *
     * @return string
     */
    public function getIntent()
    {
        return $this->intent;
    }

    /**
     * Source of the funds for this payment represented by a PayPal account or a direct credit card.
     *
     * @param \PayPal\Api\Payer $payer
     *
     * @return $this
     */
    public function setPayer($payer)
    {
        $this->payer = $payer;
        return $this;
    }

    /**
     * Source of the funds for this payment represented by a PayPal account or a direct credit card.
     *
     * @return \PayPal\Api\Payer
     */
    public function getPayer()
    {
        return $this->payer;
    }

    /**
     * Information that the merchant knows about the payer.  This information is not definitive and only serves as a hint to the UI or any pre-processing logic.
     *
     * @param \PayPal\Api\PotentialPayerInfo $potential_payer_info
     *
     * @return $this
     */
    public function setPotentialPayerInfo($potential_payer_info)
    {
        $this->potential_payer_info = $potential_payer_info;
        return $this;
    }

    /**
     * Information that the merchant knows about the payer.  This information is not definitive and only serves as a hint to the UI or any pre-processing logic.
     *
     * @return \PayPal\Api\PotentialPayerInfo
     */
    public function getPotentialPayerInfo()
    {
        return $this->potential_payer_info;
    }

    /**
     * Receiver of funds for this payment. **Readonly for PayPal external REST payments.**
     *
     * @param \PayPal\Api\Payee $payee
     *
     * @return $this
     */
    public function setPayee($payee)
    {
        $this->payee = $payee;
        return $this;
    }

    /**
     * Receiver of funds for this payment. **Readonly for PayPal external REST payments.**
     *
     * @return \PayPal\Api\Payee
     */
    public function getPayee()
    {
        return $this->payee;
    }

    /**
     * ID of the cart to execute the payment.
     *
     * @deprecated Not publicly available
     * @param string $cart
     *
     * @return $this
     */
    public function setCart($cart)
    {
        $this->cart = $cart;
        return $this;
    }

    /**
     * ID of the cart to execute the payment.
     *
     * @deprecated Not publicly available
     * @return string
     */
    public function getCart()
    {
        return $this->cart;
    }

    /**
     * Transactional details including the amount and item details.
     *
     * @param \PayPal\Api\Transaction[] $transactions
     *
     * @return $this
     */
    public function setTransactions($transactions)
    {
        $this->transactions = $transactions;
        return $this;
    }

    /**
     * Transactional details including the amount and item details.
     *
     * @return \PayPal\Api\Transaction[]
     */
    public function getTransactions()
    {
        return $this->transactions;
    }

    /**
     * Append Transactions to the list.
     *
     * @param \PayPal\Api\Transaction $transaction
     * @return $this
     */
    public function addTransaction($transaction)
    {
        if (!$this->getTransactions()) {
            return $this->setTransactions(array($transaction));
        } else {
            return $this->setTransactions(
                array_merge($this->getTransactions(), array($transaction))
            );
        }
    }

    /**
     * Remove Transactions from the list.
     *
     * @param \PayPal\Api\Transaction $transaction
     * @return $this
     */
    public function removeTransaction($transaction)
    {
        return $this->setTransactions(
            array_diff($this->getTransactions(), array($transaction))
        );
    }

    /**
     * Applicable for advanced payments like multi seller payment (MSP) to support partial failures
     *
     * @deprecated Not publicly available
     * @param \PayPal\Api\Error[] $failed_transactions
     *
     * @return $this
     */
    public function setFailedTransactions($failed_transactions)
    {
        $this->failed_transactions = $failed_transactions;
        return $this;
    }

    /**
     * Applicable for advanced payments like multi seller payment (MSP) to support partial failures
     *
     * @deprecated Not publicly available
     * @return \PayPal\Api\Error[]
     */
    public function getFailedTransactions()
    {
        return $this->failed_transactions;
    }

    /**
     * Append FailedTransactions to the list.
     *
     * @deprecated Not publicly available
     * @param \PayPal\Api\Error $error
     * @return $this
     */
    public function addFailedTransaction($error)
    {
        if (!$this->getFailedTransactions()) {
            return $this->setFailedTransactions(array($error));
        } else {
            return $this->setFailedTransactions(
                array_merge($this->getFailedTransactions(), array($error))
            );
        }
    }

    /**
     * Remove FailedTransactions from the list.
     *
     * @deprecated Not publicly available
     * @param \PayPal\Api\Error $error
     * @return $this
     */
    public function removeFailedTransaction($error)
    {
        return $this->setFailedTransactions(
            array_diff($this->getFailedTransactions(), array($error))
        );
    }

    /**
     * Collection of PayPal generated billing agreement tokens.
     *
     * @param string[] $billing_agreement_tokens
     *
     * @return $this
     */
    public function setBillingAgreementTokens($billing_agreement_tokens)
    {
        $this->billing_agreement_tokens = $billing_agreement_tokens;
        return $this;
    }

    /**
     * Collection of PayPal generated billing agreement tokens.
     *
     * @return string[]
     */
    public function getBillingAgreementTokens()
    {
        return $this->billing_agreement_tokens;
    }

    /**
     * Append BillingAgreementTokens to the list.
     *
     * @param string $billingAgreementToken
     * @return $this
     */
    public function addBillingAgreementToken($billingAgreementToken)
    {
        if (!$this->getBillingAgreementTokens()) {
            return $this->setBillingAgreementTokens(array($billingAgreementToken));
        } else {
            return $this->setBillingAgreementTokens(
                array_merge($this->getBillingAgreementTokens(), array($billingAgreementToken))
            );
        }
    }

    /**
     * Remove BillingAgreementTokens from the list.
     *
     * @param string $billingAgreementToken
     * @return $this
     */
    public function removeBillingAgreementToken($billingAgreementToken)
    {
        return $this->setBillingAgreementTokens(
            array_diff($this->getBillingAgreementTokens(), array($billingAgreementToken))
        );
    }

    /**
     * Credit financing offered to payer on PayPal side. Returned in payment after payer opts-in
     *
     * @deprecated Not publicly available
     * @param \PayPal\Api\CreditFinancingOffered $credit_financing_offered
     *
     * @return $this
     */
    public function setCreditFinancingOffered($credit_financing_offered)
    {
        $this->credit_financing_offered = $credit_financing_offered;
        return $this;
    }

    /**
     * Credit financing offered to payer on PayPal side. Returned in payment after payer opts-in
     *
     * @deprecated Not publicly available
     * @return \PayPal\Api\CreditFinancingOffered
     */
    public function getCreditFinancingOffered()
    {
        return $this->credit_financing_offered;
    }

    /**
     * Instructions for the payer to complete this payment.
     *
     * @param \PayPal\Api\PaymentInstruction $payment_instruction
     *
     * @return $this
     */
    public function setPaymentInstruction($payment_instruction)
    {
        $this->payment_instruction = $payment_instruction;
        return $this;
    }

    /**
     * Instructions for the payer to complete this payment.
     *
     * @return \PayPal\Api\PaymentInstruction
     */
    public function getPaymentInstruction()
    {
        return $this->payment_instruction;
    }

    /**
     * Payment state.
     * Valid Values: ["created", "approved", "failed", "partially_completed", "in_progress"]
     *
     * @param string $state
     *
     * @return $this
     */
    public function setState($state)
    {
        $this->state = $state;
        return $this;
    }

    /**
     * Payment state.
     *
     * @return string
     */
    public function getState()
    {
        return $this->state;
    }

    /**
     * PayPal generated identifier for the merchant's payment experience profile. Refer to [this](https://developer.paypal.com/webapps/developer/docs/api/#payment-experience) link to create experience profile ID.
     *
     * @param string $experience_profile_id
     *
     * @return $this
     */
    public function setExperienceProfileId($experience_profile_id)
    {
        $this->experience_profile_id = $experience_profile_id;
        return $this;
    }

    /**
     * PayPal generated identifier for the merchant's payment experience profile. Refer to [this](https://developer.paypal.com/webapps/developer/docs/api/#payment-experience) link to create experience profile ID.
     *
     * @return string
     */
    public function getExperienceProfileId()
    {
        return $this->experience_profile_id;
    }

    /**
     * free-form field for the use of clients to pass in a message to the payer
     *
     * @param string $note_to_payer
     *
     * @return $this
     */
    public function setNoteToPayer($note_to_payer)
    {
        $this->note_to_payer = $note_to_payer;
        return $this;
    }

    /**
     * free-form field for the use of clients to pass in a message to the payer
     *
     * @return string
     */
    public function getNoteToPayer()
    {
        return $this->note_to_payer;
    }

    /**
     * Set of redirect URLs you provide only for PayPal-based payments.
     *
     * @param \PayPal\Api\RedirectUrls $redirect_urls
     *
     * @return $this
     */
    public function setRedirectUrls($redirect_urls)
    {
        $this->redirect_urls = $redirect_urls;
        return $this;
    }

    /**
     * Set of redirect URLs you provide only for PayPal-based payments.
     *
     * @return \PayPal\Api\RedirectUrls
     */
    public function getRedirectUrls()
    {
        return $this->redirect_urls;
    }

    /**
     * Failure reason code returned when the payment failed for some valid reasons.
     * Valid Values: ["UNABLE_TO_COMPLETE_TRANSACTION", "INVALID_PAYMENT_METHOD", "PAYER_CANNOT_PAY", "CANNOT_PAY_THIS_PAYEE", "REDIRECT_REQUIRED", "PAYEE_FILTER_RESTRICTIONS"]
     *
     * @param string $failure_reason
     *
     * @return $this
     */
    public function setFailureReason($failure_reason)
    {
        $this->failure_reason = $failure_reason;
        return $this;
    }

    /**
     * Failure reason code returned when the payment failed for some valid reasons.
     *
     * @return string
     */
    public function getFailureReason()
    {
        return $this->failure_reason;
    }

    /**
     * Payment creation time as defined in [RFC 3339 Section 5.6](http://tools.ietf.org/html/rfc3339#section-5.6).
     *
     * @param string $create_time
     *
     * @return $this
     */
    public function setCreateTime($create_time)
    {
        $this->create_time = $create_time;
        return $this;
    }

    /**
     * Payment creation time as defined in [RFC 3339 Section 5.6](http://tools.ietf.org/html/rfc3339#section-5.6).
     *
     * @return string
     */
    public function getCreateTime()
    {
        return $this->create_time;
    }

    /**
     * Payment update time as defined in [RFC 3339 Section 5.6](http://tools.ietf.org/html/rfc3339#section-5.6).
     *
     * @param string $update_time
     *
     * @return $this
     */
    public function setUpdateTime($update_time)
    {
        $this->update_time = $update_time;
        return $this;
    }

    /**
     * Payment update time as defined in [RFC 3339 Section 5.6](http://tools.ietf.org/html/rfc3339#section-5.6).
     *
     * @return string
     */
    public function getUpdateTime()
    {
        return $this->update_time;
    }

    /**
     * Get Approval Link
     *
     * @return null|string
     */
    public function getApprovalLink()
    {
        return $this->getLink(PayPalConstants::APPROVAL_URL);
    }

    /**
     * Create and process a payment by passing a payment object that includes the intent, payer, and transactions in the body of the request JSON. For PayPal payments, include redirect URLs in the payment object.
     *
     * @param ApiContext     $apiContext is the APIContext for this call. It can be used to pass dynamic configuration and credentials.
     * @param PayPalRestCall $restCall   is the Rest Call Service that is used to make rest calls
     * @return Payment
     */
    public function create($apiContext = null, $restCall = null)
    {
        $payLoad = $this->toJSON();
        $json = self::executeCall(
            "/v1/payments/payment",
            "POST",
            $payLoad,
            null,
            $apiContext,
            $restCall
        );
        $this->fromJson($json);
        return $this;
    }

    /**
     * Look up a particular payment resource by passing the payment_id in the request URI.
     *
     * @param string         $paymentId
     * @param ApiContext     $apiContext is the APIContext for this call. It can be used to pass dynamic configuration and credentials.
     * @param PayPalRestCall $restCall   is the Rest Call Service that is used to make rest calls
     * @return Payment
     */
    public static function get($paymentId, $apiContext = null, $restCall = null)
    {
        ArgumentValidator::validate($paymentId, 'paymentId');
        $payLoad = "";
        $json = self::executeCall(
            "/v1/payments/payment/$paymentId",
            "GET",
            $payLoad,
            null,
            $apiContext,
            $restCall
        );
        $ret = new Payment();
        $ret->fromJson($json);
        return $ret;
    }

    /**
     * Use this call to partially update the payment resource for the given identifier. Allowed objects are amount, shipping_address, invoice_id and custom. Please note that it is not possible to use patch after execute has been called.
     *
     * @param PatchRequest   $patchRequest
     * @param ApiContext     $apiContext is the APIContext for this call. It can be used to pass dynamic configuration and credentials.
     * @param PayPalRestCall $restCall   is the Rest Call Service that is used to make rest calls
     * @return boolean
     */
    public function update($patchRequest, $apiContext = null, $restCall = null)
    {
        ArgumentValidator::validate($this->getId(), "Id");
        ArgumentValidator::validate($patchRequest, 'patchRequest');
        $payLoad = $patchRequest->toJSON();
        self::executeCall(
            "/v1/payments/payment/{$this->getId()}",
            "PATCH",
            $payLoad,
            null,
            $apiContext,
            $restCall
        );
        return true;
    }

    /**
     * Execute (complete) a PayPal payment that has been approved by the payer. Optionally update selective payment information when executing the payment.
     *
     * @param PaymentExecution $paymentExecution
     * @param ApiContext       $apiContext is the APIContext for this call. It can be used to pass dynamic configuration and credentials.
     * @param PayPalRestCall   $restCall   is the Rest Call Service that is used to make rest calls
     * @return Payment
     */
    public function execute($paymentExecution, $apiContext = null, $restCall = null)
    {
        ArgumentValidator::validate($this->getId(), "Id");
        ArgumentValidator::validate($paymentExecution, 'paymentExecution');
        $payLoad = $paymentExecution->toJSON();
        $json = self::executeCall(
            "/v1/payments/payment/{$this->getId()}/execute",
            "POST",
            $payLoad,
            null,
            $apiContext,
            $restCall
        );
        $this->fromJson($json);
        return $this;
    }

    /**
     * List payments in any state (created, approved, failed, etc.). Payments returned are the payments made to the merchant issuing the request.
     *
     * @param array          $params
     * @param ApiContext     $apiContext is the APIContext for this call. It can be used to pass dynamic configuration and credentials.
     * @param PayPalRestCall $restCall   is the Rest Call Service that is used to make rest calls
     * @return PaymentHistory
     */
    public static function all($params, $apiContext = null, $restCall = null)
    {
        ArgumentValidator::validate($params, 'params');
        $payLoad = "";
        $allowedParams = array(
            'count' => 1,
            'start_id' => 1,
            'start_index' => 1,
            'start_time' => 1,
            'end_time' => 1,
            'payee_id' => 1,
            'sort_by' => 1,
            'sort_order' => 1,
        );
        $json = self::executeCall(
            "/v1/payments/payment?" . http_build_query(array_intersect_key($params, $allowedParams)),
            "GET",
            $payLoad,
            null,
            $apiContext,
            $restCall
        );
        $ret = new PaymentHistory();
        $ret->fromJson($json);
        return $ret;
    }

}
