<?php

namespace App\Classes\Modules\Billplzs\ControllersLogic;

use App\Classes\Modules\Orders\Processors\UpdateDoFromVTPortalProcessor;
use App\Classes\Modules\Orders\Processors\UpdateDoFromYDPortalProcessor;

use App\Classes\Exceptions\ResourceNotFoundException;
use App\Classes\Modules\Wallets\Services\UpdatesWalletBalance;
use App\Models\User;
use App\Models\Wallet;
use Illuminate\Http\Request;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\Modules\Billplzs\Services\GetBillplzBill;
use App\Classes\Modules\Billplzs\DataTransferObjects\BillplzXSignatureObject;
use App\Classes\Modules\Billplzs\Processors\CallbackBillplzProcessor;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Processors\CreatePaymentTransactionProcessor;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\Modules\Transactions\Processors\CheckStorageInvoiceTransactionProcessor;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Group;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;

class CallbackBillplzLogic
{
    /** @var GetBillplzBill */
    private $getBillplzBill;

    /** @var FetchesTransaction */
    private $fetchesTransaction;

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

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

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

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

    /** @var CreatePaymentTransactionProcessor */
    private $createPaymentTransactionProcessor;

    /** @var CallbackBillplzProcessor */
    private $callbackBillplzProcessor;

    /** @var CheckStorageInvoiceTransactionProcessor */
    private $storageInvoiceTransactionProcessor;

    /**
     * CallbackBillplzLogic constructor.
     * @param GetBillplzBill $getBillplzBill
     * @param FetchesTransaction $fetchesTransaction
     * @param UpdatesTransactionStatus $updatesTransactionStatus
     * @param UpdateDoFromVTPortalProcessor $updateDoFromVTPortalProcessor
     * @param UpdateDoFromYDPortalProcessor $updateDoFromYDPortalProcessor
     * @param CreatePaymentTransactionProcessor $createPaymentTransactionProcessor
     * @param CallbackBillplzProcessor $callbackBillplzProcessor
     * @param CheckStorageInvoiceTransactionProcessor $storageInvoiceTransactionProcessor
     */
    public function __construct(GetBillplzBill $getBillplzBill, FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus, UpdateDoFromVTPortalProcessor $updateDoFromVTPortalProcessor, UpdateDoFromYDPortalProcessor $updateDoFromYDPortalProcessor, UpdatesWalletBalance $updatesWalletBalance, CreatePaymentTransactionProcessor $createPaymentTransactionProcessor, CallbackBillplzProcessor $callbackBillplzProcessor, CheckStorageInvoiceTransactionProcessor $storageInvoiceTransactionProcessor)
    {
        $this->getBillplzBill = $getBillplzBill;
        $this->fetchesTransaction = $fetchesTransaction;
        $this->updatesTransactionStatus = $updatesTransactionStatus;
        $this->updateDoFromVTPortalProcessor = $updateDoFromVTPortalProcessor;
        $this->updateDoFromYDPortalProcessor = $updateDoFromYDPortalProcessor;
        $this->updatesWalletBalance = $updatesWalletBalance;
        $this->createPaymentTransactionProcessor = $createPaymentTransactionProcessor;
        $this->callbackBillplzProcessor = $callbackBillplzProcessor;
        $this->storageInvoiceTransactionProcessor = $storageInvoiceTransactionProcessor;
    }


    /**
     * @param Request $request
     * @return bool|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
     * @throws MalformedRequestException
     * @throws ResourceNotFoundException
     * @throws \App\Classes\Exceptions\InternalServerErrorException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function execute(Request $request)
    {
        $billplzXSignatureObject = new BillplzXSignatureObject($request);

        if(!$billplzXSignatureObject->isValidSignature()){
            throw new MalformedRequestException('Billplz Payment validation failed.');
        }

        $billPlz = $this->getBillplzBill->execute($billplzXSignatureObject->getBillPlzId());

        if(!$billPlz) throw new ResourceNotFoundException('Billplz bill not found.');

        $transaction = $this->fetchesTransaction->execute(['payment_reference' => $billplzXSignatureObject->getBillPlzId()]);

        $invoice = $transaction->owner;
        $packingList = $invoice->owner;
        $order = $packingList->owner;

        $status = ApprovalStatus::PENDING_VERIFICATION;

        if($billPlz->state === 'paid') {
            $status = ApprovalStatus::APPROVED;
        }

        if($billPlz->state === 'due') {
            $status = $billplzXSignatureObject->getStatus() === 'failed' ? ApprovalStatus::REJECTED : ApprovalStatus::PENDING_VERIFICATION;
        }

        Log::info('Debug billPlz status: '.$status);

        $token = Auth::fromUser(User::find(1));
        $request->headers->set('Authorization', 'Bearer '.$token);

        $this->storageInvoiceBackDoorPreventionCheck($transaction, $status);
        $result = $this->callbackBillplzProcessor->execute($transaction, $status);

        $company_module_marking = $transaction->owner->owner->connections? $transaction->owner->owner->connections->first()->invitee_reference: null;

        if ($transaction->owner instanceof Wallet) {
            $company_module_marking = $transaction->owner->owner->connections? $transaction->owner->owner->connections->first()->invitee_reference: null;
        } else {

            $company_module_marking = $order->companyModule->connections? $order->companyModule->connections->first()->invitee_reference: null;
        }

        return $request->method() === 'POST' ? true : view('pages.payments_redirect', ['marking' => $order->reference ?? null, 'company_module_marking' => $company_module_marking ?? null, 'transaction' => $transaction, 'status' => $status, 'result' => $result]);
    }

    private function storageInvoiceBackDoorPreventionCheck($transaction, $status){
        if ($transaction->owner instanceof Wallet && $status === ApprovalStatus::APPROVED) {
            $group = Group::where('reference', $transaction->payment_reference)->first();
            if ($group) {
                foreach ($group->groupTransactions as $groupTransaction) {
                    $invoice = $groupTransaction->transaction;
                    $pL = $invoice->owner;
                    $order = $pL->owner;
                    if($order){
                        $this->storageInvoiceTransactionProcessor->executeOrder($order);
                    }
                }
            }
        }
    }
}
