<?php

namespace GlobalPayments\Api\Terminals\Builders;

use GlobalPayments\Api\Entities\AutoSubstantiation;
use GlobalPayments\Api\Entities\LodgingData;
use GlobalPayments\Api\Terminals\Entities\HostData;
use GlobalPayments\Api\Terminals\Enums\AcquisitionType;
use GlobalPayments\Api\Entities\Enums\{
    PaymentMethodType,
    StoredCredentialInitiator,
    TaxType,
    TransactionModifier,
    TransactionType
};
use GlobalPayments\Api\PaymentMethods\{CreditCardData, TransactionReference};
use GlobalPayments\Api\ServicesContainer;
use GlobalPayments\Api\Terminals\Enums\CurrencyType;
use GlobalPayments\Api\Terminals\TerminalResponse;

class TerminalAuthBuilder extends TerminalBuilder
{

    public mixed $address = null;

    public ?bool $allowDuplicates = null;

    public float|int|string|null $amount = null;

    public ?string $authCode = null;

    public float|int|string|null $cashBackAmount = null;

    /**
     * 
     * @var string|int|float
     */
    public string|int|float|null $tippableAmount = null;

    public ?string $currency = null;

    public ?string $customerCode = null;

    public float|int|string|null $gratuity = null;

    public ?string $invoiceNumber = null;

    public ?string $poNumber = null;

    public ?bool $requestMultiUseToken = null;

    public ?bool $signatureCapture = null;

    public float|int|string|null $taxAmount = null;

    public ?bool $taxExempt = null;

    public ?string $taxExemptId = null;

    public ?string $transactionId = null;

    public ?string $shiftId = null;

    public mixed $taxType = null;
    
    public mixed $tokenRequest = null;
    
    public ?string $tokenValue = null;
    
    /**
     * 
     * @var AutoSubstantiation
     */
    public ?AutoSubstantiation $autoSubstantiation = null;

    public ?string $terminalRefNumber = null;

    public ?LodgingData $lodgingData = null;

    public ?\DateTime $shippingDate = null;

    public ?int $processCPC = null;

    public ?bool $confirmAmount = null;

    /**
     * 
     * @var bool
     */
    public ?bool $allowPartialAuth = null;

    /**
     * 
     * @var StoredCredentialInitiator
     */
    public mixed $transactionInitiator = null;

    public ?bool $isQuickChip = null;
    public ?bool $hasCheckLuhn = null;
    public ?bool $hasSecurityCode = null;
    public array $cardTypeFilter = [];
    public ?\DateTime $transactionDate = null;
    /** @var int Number of seconds for timeout */
    public ?int $timeout = null;
    /** @var array<AcquisitionType> */
    public array $acquisitionTypes = [];
    public ?bool $displayTotalAmount = null;
    /** @var string|PromptForManualEntryPassword  */
    public ?string $promptForManualEntryPassword = null;
    public ?string $merchantDecision = null;
    public ?string $language = null;
    public ?HostData $hostData = null;
    public ?string $directMarketInvoiceNumber = null;
    public ?int $directMarketShipMonth = null;
    public ?int $directMarketShipDay = null;

    /** @var mixed The amount previously authorized for a pre-auth transaction */
    public mixed $preAuthAmount = null;

    /**
     *
     * {@inheritdoc}
     *
     * @param TransactionType $transactionType
     *            Request transaction type
     * @param PaymentMethodType $paymentMethodType
     *            Request payment method
     *
     * @return
     */
    public function __construct($transactionType, $paymentMethodType = null)
    {
        parent::__construct($transactionType, $paymentMethodType);
        $this->transactionType = $transactionType;
        $this->paymentMethodType = $paymentMethodType;
    }

    /**
     * @param string $configName
     * @return TerminalResponse
     * @throws \GlobalPayments\Api\Entities\Exceptions\ApiException
     */
    public function execute(string $configName = "default") : TerminalResponse
    {
        parent::execute($configName);
        $client = ServicesContainer::instance()->getDeviceController($configName);

        return $client->processTransaction($this);
    }

    public function withAddress($address)
    {
        $this->address = $address;
        return $this;
    }

    public function withAllowDuplicates($allowDuplicates)
    {
        $this->allowDuplicates = $allowDuplicates;
        return $this;
    }

    public function withAmount($amount)
    {
        $this->amount = $amount;
        return $this;
    }

    public function withCashBack($amount)
    {
        $this->cashBackAmount = $amount;
        return $this;
    }

    /**
     * 
     * @param string|int|float $tippableAmount 
     * @return $this 
     */
    public function withTippableAmount(string|int|float $tippableAmount) : TerminalAuthBuilder
    {
        $this->tippableAmount = $tippableAmount;
        return $this;
    }

    public function withCurrency($value)
    {
        $this->currency = $value;
        return $this;
    }

    public function withCustomerCode($customerCode)
    {
        $this->customerCode = $customerCode;
        return $this;
    }

    public function withGratuity($gratuity)
    {
        $this->gratuity = $gratuity;
        return $this;
    }

    public function withInvoiceNumber($invoiceNumber)
    {
        $this->invoiceNumber = $invoiceNumber;
        return $this;
    }

    public function withPaymentMethod($method)
    {
        $this->paymentMethod = $method;
        return $this;
    }

    public function withPoNumber($poNumber)
    {
        $this->poNumber = $poNumber;
        return $this;
    }

    public function withRequestMultiUseToken($requestMultiUseToken)
    {
        $this->requestMultiUseToken = $requestMultiUseToken;
        return $this;
    }

    public function withSignatureCapture($signatureCapture)
    {
        $this->signatureCapture = $signatureCapture;
        return $this;
    }

    public function withTaxAmount($taxAmount)
    {
        $this->taxAmount = $taxAmount;
        return $this;
    }

    public function withToken($value)
    {
        if ($this->paymentMethod == null || !($this->paymentMethod instanceof CreditCardData)) {
            $this->paymentMethod = new CreditCardData();
            $this->paymentMethod->token = $value;
        }
        return $this;
    }

    /**
     * Previous request's transaction ID
     *
     * @param string $transactionId
     * @return $this
     */
    public function withTransactionId(string $transactionId)
    {
        if ($this->paymentMethod == null || !$this->paymentMethod instanceof TransactionReference) {
            $this->paymentMethod = new TransactionReference();
            $this->paymentMethod->transactionId = $transactionId;
        }
        $this->transactionId = $transactionId;
        return $this;
    }

    /**
     * 
     * @param null|StoredCredentialInitiator|string $transactionInitiator 
     * @param string|null $cardBrandTransactionId 
     * @return TerminalAuthBuilder 
     */
    public function withCardBrandStorage(
        StoredCredentialInitiator|string $transactionInitiator = null,
        string $cardBrandTransactionId = null
    )
    {
        $this->cardBrandTransId = $cardBrandTransactionId;
        $this->transactionInitiator = $transactionInitiator;
        return $this;
    }
  
    public function withEcrId(string $ecrId)
    {
        $this->ecrId = $ecrId;
        return $this;
    }

    public function withTerminalRefNumber(string $terminalRefNumber)
    {
        $this->terminalRefNumber = $terminalRefNumber;
        return $this;
    }

    protected function setupValidations()
    {
        $this->validations->of(TransactionType::AUTH | TransactionType::SALE | TransactionType::REFUND)
            ->with(TransactionModifier::NONE)
            ->check('amount')
            ->isNotNull();

        $this->validations->of(TransactionType::REFUND)
            ->check('amount')
            ->isNotNull();

        $this->validations->of(TransactionType::REFUND)
            ->with(PaymentMethodType::CREDIT)
            ->check('transactionId')
            ->isNotNull()
            ->check('authCode')
            ->isNotNull();

        $this->validations->of(TransactionType::ADD_VALUE)
            ->check('amount')
            ->isNotNull();

        $this->validations->of(TransactionType::BALANCE)
            ->check("currency")
            ->isNotNull()
            ->check("currency")
            ->isNotEqualTo(CurrencyType::VOUCHER);

        $this->validations->of(TransactionType::BENEFIT_WITHDRAWAL)
            ->check("currency")
            ->isNotNull()
            ->check("currency")
            ->isEqualTo(CurrencyType::CASH_BENEFITS);

        $this->validations->of(TransactionType::REFUND)
            ->with(PaymentMethodType::EBT)
            ->check("allowDuplicates")
            ->isEqualTo(false);

        $this->validations->of(TransactionType::BENEFIT_WITHDRAWAL)
            ->with(PaymentMethodType::EBT)
            ->check("allowDuplicates")
            ->isEqualTo(false);
    }

    public function withTaxType($taxType, $taxExemptId = null)
    {
        $this->taxType = $taxType;
        $this->taxExempt = ($taxType === TaxType::TAX_EXEMPT) ? 1 : 0;
        $this->taxExemptId = $taxExemptId;
        return $this;
    }
    
    public function withClientTransactionId($clientTransactionId)
    {
        $this->clientTransactionId = $clientTransactionId;
        return $this;
    } 
    
    /**
     * 
     * @param AutoSubstantiation $healthCareCardData 
     * @return $this 
     */
    public function withAutoSubstantiation(AutoSubstantiation $healthCareCardData)
    {
        $this->autoSubstantiation = $healthCareCardData;
        return $this;
    }

    /**
     * 
     * @param bool $value 
     * @return $this 
     */
    public function withAllowPartialAuth(bool $value)
    {
        $this->allowPartialAuth = $value;
        return $this;
    }

    public function withLodgingData(LodgingData $lodgingData)
    {
        $this->lodgingData = $lodgingData;
        return $this;
    }

    public function withShippingDate(\DateTime $date)
    {
        $this->shippingDate = $date;
        return $this;
    }

    public function withProcessCPC(bool $processCPC)
    {
        $this->processCPC = (int) $processCPC;
        return $this;
    }

    public function withConfirmationAmount(bool $value) : TerminalAuthBuilder
    {
        $this->confirmAmount = $value;
        return $this;
    }

    public function withQuickChip(bool $value) : TerminalAuthBuilder
    {
        $this->isQuickChip = $value;
        return $this;
    }

    public function withCheckLuhn(bool $value) : TerminalAuthBuilder
    {
        $this->hasCheckLuhn = $value;
        return $this;
    }

    public function withSecurityCode(bool $value) : TerminalAuthBuilder
    {
        $this->hasSecurityCode = $value;
        return $this;
    }

    public function withCardTypeFilter(array $cardTypeFilter) : TerminalAuthBuilder
    {
        $this->cardTypeFilter = $cardTypeFilter;
        return $this;
    }

    public function withTransactionDate(\DateTime $date) : TerminalAuthBuilder
    {
        $this->transactionDate = $date;
        return $this;
    }

    public function withTimeout(int $timeout) : TerminalAuthBuilder
    {
        $this->timeout = $timeout;
        return $this;
    }
    public function withAcquisitionTypes(array $acquisitionTypes) : TerminalAuthBuilder
    {
        $this->acquisitionTypes = $acquisitionTypes;
        return $this;
    }

    public function withDisplayTotalAmount(bool $value) : TerminalAuthBuilder
    {
        $this->displayTotalAmount = $value;
        return $this;
    }

    public function withPromptForManualEntryPassword(string $value) : TerminalAuthBuilder
    {
        $this->promptForManualEntryPassword = $value;
        return $this;
    }

    public function withMerchantDecision(string $merchantDecision) : TerminalAuthBuilder
    {
        $this->merchantDecision = $merchantDecision;
        return $this;
    }

    public function withLanguage(string $language) : TerminalAuthBuilder
    {
        $this->language = $language;
        return $this;
    }

    public function withHostData(HostData $hostData) : TerminalAuthBuilder
    {
        $this->hostData = $hostData;
        return $this;
    }

     /**
     * Set the pre-auth amount for incremental or completion transactions.
     *
     * @param mixed $preAuthAmount
     * @return TerminalManageBuilder
     */
    public function withPreAuthAmount($preAuthAmount)
    {
        $this->preAuthAmount = $preAuthAmount;
        return $this;
    }

    public function withTokenRequest($tokenRequest)
    {
        $this->tokenRequest = $tokenRequest;
        return $this;
    }

    public function withTokenValue($tokenValue)
    {
        $this->tokenValue = $tokenValue;
        return $this;
    }

    public function withDirectMarketInvoiceNumber($directMarketInvoiceNumber)
    {
        $this->directMarketInvoiceNumber = $directMarketInvoiceNumber;
        return $this;
    }

    public function withDirectMarketShipMonth($directMarketShipMonth)
    {
        $this->directMarketShipMonth = $directMarketShipMonth;
        return $this;
    }

    public function withDirectMarketShipDay($directMarketShipDay)
    {
        $this->directMarketShipDay = $directMarketShipDay;
        return $this;
    }
}
