<?php

namespace App\Classes\Modules\Transactions\Processors;

use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Modules\Bookings\Services\CalculatesBookingPayableAmount;
use App\Classes\Modules\Bookings\Services\CalculatesBookingTransferredAmount;
use App\Classes\Modules\ServiceTypes\Services\FetchesServiceConfigurations;
use App\Classes\Modules\Transactions\Services\ListsTransactions;
use App\Classes\Modules\Transactions\Services\CreatesTransaction;
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
use App\Classes\Modules\Bookings\Services\CalculatesBookingPaidAmount;
use App\Classes\Modules\Bookings\Services\CalculatesBookingCurrencyAverageRate;
use App\Classes\Modules\Companies\Services\FetchesCompany;
use App\Classes\Modules\Bookings\Services\UpdatesBookingStatus;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\SegmentConstants;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Models\Booking;
use App\Models\SegmentConstant;

/**
 * @deprecated This class is deprecated and should not be used.
 * Use `CreateInvoiceTransactionProcessor` instead or write a new one based on CreateInvoiceTransactionProcessor
 */
class CreateInvoiceTransactionWithInvoiceNoProcessor
{

    /** @var CreatesTransaction */
    private $createsTransaction;

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

    /** @var CalculatesBookingPaidAmount */
    private $calculatesBookingPaidAmount;

    /** @var CalculatesBookingPayableAmount */
    private $calculatesBookingPayableAmount;

    /** @var CalculatesBookingTransferredAmount */
    private $calculatesBookingTransferredAmount;

    /** @var CalculatesBookingCurrencyAverageRate */
    private $calculatesBookingCurrencyAverageRate;

    /** @var FetchesCompany */
    private $fetchesCompany;

    /** @var UpdatesBookingStatus */
    private $updatesBookingStatus;

    /** @var CreateInvoiceDocumentProcessor */
    private $invoiceDocumentProcessor;


    /**
     * CreateInvoiceTransactionWithInvoiceNoProcessor constructor.
     * @param ListsTransactions $listsTransactions
     * @param CreatesTransaction $createsTransaction
     * @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
     * @param CalculatesBookingPaidAmount $calculatesBookingPaidAmount
     * @param CalculatesBookingPayableAmount $calculatesBookingPayableAmount
     * @param CalculatesBookingTransferredAmount $calculatesBookingTransferredAmount
     * @param FetchesServiceConfigurations $fetchesServiceConfigurations
     * @param CalculatesBookingCurrencyAverageRate $calculatesBookingCurrencyAverageRate
     * @param FetchesCompany $fetchesCompany
     * @param UpdatesBookingStatus $updatesBookingStatus
     * @param CreateInvoiceDocumentProcessor $invoiceDocumentProcessor
     */
    public function __construct(ListsTransactions $listsTransactions, CreatesTransaction $createsTransaction, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CalculatesBookingPaidAmount $calculatesBookingPaidAmount, CalculatesBookingPayableAmount $calculatesBookingPayableAmount, CalculatesBookingTransferredAmount $calculatesBookingTransferredAmount, FetchesServiceConfigurations $fetchesServiceConfigurations, CalculatesBookingCurrencyAverageRate $calculatesBookingCurrencyAverageRate, FetchesCompany $fetchesCompany, UpdatesBookingStatus $updatesBookingStatus, CreateInvoiceDocumentProcessor $invoiceDocumentProcessor)
    {
        $this->createsTransaction = $createsTransaction;
        $this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
        $this->calculatesBookingPaidAmount = $calculatesBookingPaidAmount;
        $this->calculatesBookingPayableAmount = $calculatesBookingPayableAmount;
        $this->calculatesBookingTransferredAmount = $calculatesBookingTransferredAmount;
        $this->calculatesBookingCurrencyAverageRate = $calculatesBookingCurrencyAverageRate;
        $this->fetchesCompany = $fetchesCompany;
        $this->updatesBookingStatus = $updatesBookingStatus;
        $this->invoiceDocumentProcessor = $invoiceDocumentProcessor;
    }



    /**
     * @param Booking $booking
     * @return void
     * @throws MalformedRequestException
     */
    public function execute(Booking $booking, String $invoiceNo)
    {

        if ($booking->status === ApprovalStatus::COMPLETED) {
            return;
        }

        $payable_amount = $this->calculatesBookingPayableAmount->execute($booking, $booking->fix_currency_id);
        $booking_amount = $booking->fix_amount;

        // confirm that booking amount has been fully paid
        if ((float) $booking_amount > (float) $payable_amount) {
            return;
        }
        // confirm that all payments has been transferred
        if ($this->calculatesBookingTransferredAmount->execute($booking) !== $this->calculatesBookingPaidAmount->execute($booking)) {
            return;
        }

        $purchaseOrder = $booking->transactions()
            ->where('type', TransactionType::PURCHASE_ORDER)
            ->complete()
            ->first();

        $constants = SegmentConstant::where('reference', SegmentConstants::SERVICE_TYPE)->where('detail->id', $booking->service->id)->first();

        if ($constants->detail->is_billable && !$purchaseOrder) {
            return;
        }

        // $transaction = $booking->transactions()
        //     ->where('type', TransactionType::PAYMENT)
        //     ->first();

        $transaction = $booking->transactions()
        ->where('type', TransactionType::PAYMENT)
        ->latest()->get()[0];

        // $billNumber = $this->generatesTransactionBillNumber->execute('INV-');
        $billNumber = $invoiceNo;

        $booking_currency_average_rate = $this->calculatesBookingCurrencyAverageRate->execute($booking, TransactionType::PAYMENT);

        $total_service_charge = $booking->transactions()
            ->where('type', TransactionType::PAYMENT)
            ->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])
            ->sum('service_charge');

        $total_tax = $booking->transactions()
            ->where('type', TransactionType::PAYMENT)
            ->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])
            ->sum('tax');

        $transaction_object = new TransactionObject(
            $billNumber,
            TransactionType::INVOICE,
            $transaction->issuer,
            $transaction->receiver,
            $transaction->recipient_bank_account_id,
            $transaction->payment_method,
            $payable_amount,
            $booking_amount,
            $transaction->currency_id,
            $transaction->original_currency_id,
            $booking_currency_average_rate,
            $total_tax,
            $total_service_charge,
            null,
            ApprovalStatus::APPROVED
        );
        $invoice_transaction = $this->createsTransaction->execute($purchaseOrder->booking, $transaction_object);

        $voucherRedemption = $transaction->voucherRedemption;

        $supplier = $this->fetchesCompany->execute(['id' => $transaction->receiver]);

        // purchase order
        $this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::PURCHASE_ORDER, $voucherRedemption);

        // deliver order
        $this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::DELIVER_ORDER, $voucherRedemption);

        // invoice
        $this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::INVOICE, $voucherRedemption);

        $billNumber = $this->generatesTransactionBillNumber->execute('SPDO-');

        $booking_currency_average_rate = $this->calculatesBookingCurrencyAverageRate->execute($booking, TransactionType::BILL);

        $transaction = $booking->transactions()->payments()->where('status', ApprovalStatus::COMPLETED)->first()
            ->transactions()->where('type', TransactionType::BILL)->first();

        $transaction_object = new TransactionObject(
            $billNumber,
            TransactionType::SUPPLIER_DELIVER,
            $transaction->issuer,
            $transaction->receiver,
            $transaction->recipient_bank_account_id,
            $transaction->payment_method,
            $payable_amount,
            $booking_amount,
            $transaction->currency_id,
            $transaction->original_currency_id,
            $booking_currency_average_rate,
            $total_tax,
            $total_service_charge,
            null,
            ApprovalStatus::APPROVED
        );
        $supplier_deliver_order_transaction = $this->createsTransaction->execute($purchaseOrder->booking, $transaction_object);

        // supply deliver order
        $this->invoiceDocumentProcessor->execute($supplier_deliver_order_transaction, $purchaseOrder, $supplier, DocumentType::SUPPLIER_DELIVER_ORDER, null);

        $this->updatesBookingStatus->execute($booking, ApprovalStatus::COMPLETED);

        // update perfex crm
        // if(config('perfexcrm.is_enabled') == 'true'){
        //     CreatePerfexCRMInvoice::dispatch($invoice_transaction, $purchaseOrder, $supplier);
        // }
    }
}
