<?php

namespace App\Console\Commands;

use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Booking;
use Illuminate\Console\Command;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use App\Classes\Modules\Bookings\Services\UpdatesBookingStatus;
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;

class ExpiredRefundedBookingCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'RefundedBooking:expired';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Expiring refunded booking';

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

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

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

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct(UpdatesBookingStatus $updatesBookingStatus, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatesTransaction $createsTransaction)
    {
        parent::__construct();
        $this->updatesBookingStatus = $updatesBookingStatus;
        $this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
        $this->createsTransaction = $createsTransaction;
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        // 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();
                        }
                        $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);

                    if (abs($amountDifference) < 0.01) {
                        // rejecting booking payment transaction
                        // $bookingPayment->status = ApprovalStatus::REJECTED;
                        // $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 ($bookingInWhiteForm) {
                        Log::info("Credit note transaction id: {$transaction->id}, booking is in white form");
                    }

                    if (!$refund && !$bookingInWhiteForm) {
                        $billNumber = $this->generatesTransactionBillNumber->execute('RFD-');

                        $object = new TransactionObject($billNumber, TransactionType::REFUND, 1, $booking->company->id,
                            1, PaymentMethodType::CASH,
                            $transaction->amount, $transaction->amount * $bookingPayment->currency_rate, 1,
                            $bookingPayment->original_currency_id, $bookingPayment->currency_rate,
                            0, 0, null, ApprovalStatus::APPROVED, [], $bookingPayment->bill_no);
    
                        $transaction = $this->createsTransaction->execute($bookingPayment, $object);
                    }
                } 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}");
            }
        }
    }
}
