<?php

namespace App\Classes\Jobs\Commands\V2;

use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Booking;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\Modules\Transactions\Services\CreatesTransaction;
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Models\Transaction;
use Illuminate\Support\Facades\Log;


class ExpiredRefundedBookingV2CommandJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;


    public function handle()
    {
        Log::info(Carbon::now() . ': Start job - Expiring refunded booking.');
        $start   = new Carbon();

        // 3. Cancel fully refunded payment & cancel booking
        $transactions = Transaction::where('type', TransactionType::CREDIT_NOTE)->where('payment_reference', 'LIKE', "%refund%")->get();

        foreach ($transactions as $transaction) {
            // get the booking marking
            $payment_reference = explode(" ", trim($transaction->payment_reference));
            // $marking = substr($transaction->payment_reference, -5);
            $marking = trim(end($payment_reference));

            if (!preg_match('/^[0-9]+$/', $marking)) {
                $payment_reference = explode(".", trim($transaction->payment_reference));
                $marking = trim(end($payment_reference));
            }

            // for a special payment reference on transaction id: 140231
            if (!preg_match('/^[0-9]+$/', $marking)) {
                $payment_reference = explode("No", trim($transaction->payment_reference));
                $marking = end($payment_reference);
            }

            // for a special payment reference on transaction id: 152013
            if (!preg_match('/^[0-9]+$/', $marking)) {
                $payment_reference = explode(" ", trim($transaction->payment_reference));
                $marking = end($payment_reference);
                $marking = prev($payment_reference);
            }

            if (preg_match('/^[0-9]+$/', $marking)) {
                $booking = Booking::where('marking', $marking)->first();

                if ($booking) {
                    $bookingPayment = $booking->transactions()->payments()->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->first();
                    if (!$bookingPayment) {
                        $bookingPaymentCount = $booking->transactions()->payments()->count();
                        if ($bookingPaymentCount > 1) {
                            Log::info("Credit note transaction id: {$transaction->id}, there are {$bookingPaymentCount} payment for the booking.");
                            foreach ($booking->transactions()->payments()->get() as $bp) {
                                if ($transaction->amount - $bp->amount < 0.01) {
                                    $bookingPayment = $bp;
                                    break;
                                }
                            }
                        }

                        if (!$bookingPayment) {
                            $bookingPayment = $booking->transactions()->payments()->whereIn('status', [ApprovalStatus::SUSPENDED, ApprovalStatus::EXPIRED, ApprovalStatus::REJECTED])->orderBy('id', 'DESC')->first();
                        }
                    }

                    if ($bookingPayment) {
                        $status = ApprovalStatus::APPROVAL_STATUS_ID[$bookingPayment->status];
                        Log::info("Credit note transaction id: {$transaction->id}, the payment for the booking is in status {$status}");

                        $bookingPaymentAmount = $bookingPayment->amount;
                        // check if the booking is fully refund
                        $amountDifference = bcsub($transaction->amount, $bookingPaymentAmount, 7);

                        $isFullyRefund = false;
                        if (abs($amountDifference) < 0.01) {
                            $isFullyRefund = true;
                            // update fully refunded booking payment transaction
                            $bookingPayment->status = ApprovalStatus::REFUNDED;
                            $bookingPayment->save();

                            //expired booking
                            // $this->updatesBookingStatus->execute($booking, ApprovalStatus::EXPIRED);
                            Log::info("Credit note transaction id: {$transaction->id} is fully refunded, the refunded amount was {$transaction->amount} the payment reference is: {$transaction->payment_reference}");
                            // Log::info("Credit note transaction id: {$transaction->id}, Rejected Booking Transaction Payment id: {$bookingPayment->id}, the payment amount was {$bookingPayment->amount}");
                            // Log::info("Credit note transaction id: {$transaction->id}, Expired Booking id: {$booking->id}");
                        } else {
                            Log::info("Credit note transaction id: {$transaction->id} is not fully refunded, the refunded amount was {$transaction->amount}, the payment amount was {$bookingPayment->amount}, the payment reference is: {$transaction->payment_reference}");
                        }

                        $refund = $bookingPayment->transactions()->refunds()->where('amount', $transaction->amount)->where('status', ApprovalStatus::APPROVED)->first();

                        $bookingInWhiteForm = $bookingPayment->transactions()->bills()->first();

                        if ($refund) {
                            Log::info("Credit note transaction id: {$transaction->id}, already created same amount of refund transaction for same booking payment transaction");
                        }

                        if (!$refund) {
                            $billNumber = (App()->make(GeneratesTransactionBillNumber::class))->execute('RFD-');

                            $object = new TransactionObject($billNumber, TransactionType::REFUND, 1, $booking->company->id,
                                1, PaymentMethodType::CASH,
                                $transaction->amount, $isFullyRefund ? $bookingPayment->original_amount : $transaction->amount * $bookingPayment->currency_rate, 1,
                                $bookingPayment->original_currency_id, $bookingPayment->currency_rate,
                                0, 0, null, ApprovalStatus::APPROVED, [], $bookingPayment->bill_no);

                            $transaction = (App()->make(CreatesTransaction::class))->execute($bookingPayment, $object);
                        }

                        if ($bookingInWhiteForm) {
                            $original_amount = $isFullyRefund ? $bookingPayment->original_amount : bcmul($transaction->amount, $bookingPayment->currency_rate, 7);
                            $supplier_refund_amount = bcdiv($original_amount, $bookingInWhiteForm->currency_rate, 7);

                            Log::info("Credit note transaction id: {$transaction->id}, booking is in white form, white form currency rate is {$bookingInWhiteForm->currency_rate}");

                            // if ($isFullyRefund && $bookingInWhiteForm->currency_rate == 1) {
                            //     dd ($bookingInWhiteForm->owner_id);
                            // }

                            $refund = $bookingPayment->transactions()->supplierRefunds()->where('original_amount', $original_amount)->first();

                            if (!$refund) {
                                $billNumber = (App()->make(GeneratesTransactionBillNumber::class))->execute('SRFD-');

                                $object = new TransactionObject($billNumber, TransactionType::SUPPLIER_REFUND, 1, $bookingInWhiteForm->issuer,
                                    1, PaymentMethodType::CASH,
                                    $supplier_refund_amount, $original_amount, 1,
                                    $bookingPayment->original_currency_id, $bookingInWhiteForm->currency_rate,
                                    0, 0, null, ApprovalStatus::APPROVED, [], $bookingPayment->bill_no);

                                $transaction = (App()->make(CreatesTransaction::class))->execute($bookingPayment, $object);
                            }
                        }
                    } else {
                        // $bookingPayment = $booking->transactions()->payments()->where('status', ApprovalStatus::REFUNDED)->orderBy('id', 'DESC')->first();

                        // if ($bookingPayment) {
                        //     Log::info("Credit note transaction id: {$transaction->id}, booking payment refunded");
                        // } else {
                            Log::info("Credit note transaction id: {$transaction->id}, booking payment not found, the payment reference is: {$transaction->payment_reference}");
                        // }
                    }
                } else {
                    Log::info("Credit note transaction id: {$transaction->id}, booking marking not found, the payment reference is: {$transaction->payment_reference}");
                }
            } else {
                Log::info("Credit note transaction id: {$transaction->id} does not have booking marking, the payment reference is: {$transaction->payment_reference}");
            }
        }


        $end = new Carbon();
        $elapsedTime = $start->diff($end)->format('%H:%I:%S');
        Log::info(Carbon::now() . ': End job - Expiring refunded booking. ElapsedTime: ' . $elapsedTime . '.');
    }
}
