<?php


namespace App\Classes\Modules\Transactions\Processors;

use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
use App\Classes\Modules\Transactions\Services\CreatesPaymentTransaction;
use App\Classes\Modules\Transactions\Services\CreatesTransactionDetail;
use App\Classes\Modules\Billplzs\Services\CreatesBillplzBill;
use App\Classes\Modules\Transactions\Services\CreatesTransactionableTransaction;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\Modules\Wallets\Services\UpdatesWalletBalance;
use App\Models\Transaction;
use App\Models\Wallet;
use App\Classes\Modules\Orders\Processors\UpdateDoFromVTPortalProcessor;
use App\Classes\Modules\Orders\Processors\UpdateDoFromYDPortalProcessor;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use Illuminate\Support\Facades\Log;

class CreatePaymentTransactionProcessor
{

    /** @var GeneratesTransactionBillNumber */
    private $generatesTransactionBillNumber;

    /** @var CreatesPaymentTransaction */
    private $createsPaymentTransaction;

    /** @var CreatesBillplzBill */
    private $createsBillplzBill;

    /** @var CreatesTransactionableTransaction */
    private $createsTransactionableTransaction;

    /** @var UpdatesWalletBalance */
    private $updatesWalletBalance;

    /** @var UpdateDoFromVTPortalProcessor */
    private $updateDoFromVTPortalProcessor;

    /** @var UpdateDoFromYDPortalProcessor */
    private $updateDoFromYDPortalProcessor ;

    /** @var UpdatesTransactionStatus */
    private $updatesTransactionStatus ;

    /**
     * @param FetchesTransaction $fetchesTransaction,
     * @param GeneratesTransactionBillNumber $generatesTransactionBillNumber,
     * @param CreatesPaymentTransaction $createsPaymentTransaction
     * @param CreatesTransactionDetail $createsTransactionDetail
     * @param CreatesBillplzBill $createsBillplzBil
     * @param CreatesTransactionableTransaction $createsTransactionableTransaction
     * @param UpdatesWalletBalance $updatesWalletBalance
     * @param UpdateDoFromVTPortalProcessor $updateDoFromVTPortalProcessor
     * @param UpdateDoFromYDPortalProcessor $updateDoFromYDPortalProcessor
     * @param UpdatesTransactionStatus $updatesTransactionStatus
     */
    public function __construct(
        GeneratesTransactionBillNumber $generatesTransactionBillNumber,
        CreatesPaymentTransaction $createsPaymentTransaction,
        CreatesBillplzBill $createsBillplzBill,
        CreatesTransactionableTransaction $createsTransactionableTransaction,
        UpdatesWalletBalance $updatesWalletBalance,
        UpdateDoFromVTPortalProcessor $updateDoFromVTPortalProcessor,
        UpdateDoFromYDPortalProcessor $updateDoFromYDPortalProcessor,
        UpdatesTransactionStatus $updatesTransactionStatus
    )
    {
        $this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
        $this->createsPaymentTransaction = $createsPaymentTransaction;
        $this->createsBillplzBill = $createsBillplzBill;
        $this->createsTransactionableTransaction = $createsTransactionableTransaction;
        $this->updatesWalletBalance = $updatesWalletBalance;
        $this->updateDoFromVTPortalProcessor = $updateDoFromVTPortalProcessor;
        $this->updateDoFromYDPortalProcessor = $updateDoFromYDPortalProcessor;
        $this->updatesTransactionStatus = $updatesTransactionStatus;
    }

    /**
     * @throws MalformedRequestException
     */
    public function execute(Transaction $invoice, $payment_method, $bank_code, $run = true)
    {
        $amount             = $invoice->amount;
        Log::info($invoice->owner);
        $company_module     = $invoice->owner->owner->companyModule()->first();
        $approvalStatus     = ApprovalStatus::PENDING_SUBMISSION;
        $billNumber         = $this->generatesTransactionBillNumber->execute('PYMT-');
        $payment_reference  = null;

        if ($payment_method == PaymentMethodType::PAYMENT_GATEWAY) {

            // create billplz transaction
            $payment_method = PaymentMethodType::PAYMENT_GATEWAY;
            $billPlzBill = $this->createsBillplzBill->execute(
                $company_module->name,
                (app()->environment(['production'])) ? $company_module->employees()->first()->email : 'uldvstar@gmail.com',
                'This payment is for the invoice number . ' . $billNumber,
                $amount,
                $billNumber,
                $bank_code,
                true
            );

            $payment_reference = $billPlzBill->id;
        }
        else if ($payment_method === PaymentMethodType::WALLET) {
            /** @var Wallet $wallet */
            $wallet = $company_module->wallets()->first();

            if((float) number_format(($wallet->amount - $amount),2) < 0){
                throw new MalformedRequestException('Insufficient wallet balance. Please Top up your wallet.');
            }

            $walletPaymentBillNumber = $this->generatesTransactionBillNumber->execute('PYMT-');

            $transaction_object = new TransactionObject($walletPaymentBillNumber, TransactionType::PAYMENT, 1, $company_module->id, 1, PaymentMethodType::WALLET, $amount, $amount, 1, 1, 1, 0, 0, null, ApprovalStatus::APPROVED, [], '');
            $transaction = $this->createsTransactionableTransaction->execute($wallet, $transaction_object);

            $payment_reference = $walletPaymentBillNumber;

            $this->updatesWalletBalance->execute($wallet, ($amount * -1));

            if($run)
            {
                $packingList = $invoice->owner;
                $order = $packingList->owner;
                $packingList->status = ApprovalStatus::APPROVED;
                $packingList->save();

                if(app()->environment('production')){
                    $this->updateDoFromVTPortalProcessor->execute($packingList);
                    $this->updateDoFromYDPortalProcessor->execute($packingList);
                }
            }

            // later use this variabke to create a approved payment transaction
            $approvalStatus = ApprovalStatus::APPROVED;

            // update invoice to completed
            if($run){
                $this->updatesTransactionStatus->execute($invoice, ApprovalStatus::COMPLETED);
            }
        }
        else {
            $payment_method = PaymentMethodType::CASH;
        }

        $object = new TransactionObject(
            $billNumber,
            TransactionType::PAYMENT,
            $company_module->id,
            1,
            1,
            $payment_method,
            $amount,
            $amount,
            1,
            1,
            0,
            0,
            0,
            null,
            $approvalStatus,
            null,
            $payment_reference
        );

        $payment_transaction = $this->createsPaymentTransaction->execute($invoice, $object);

        return $payment_transaction;
    }
}
