<?php

namespace App\Classes\Jobs\Commands\V2;

use App\Classes\Modules\Bookings\Processors\RegenerateInvoiceBookingV2Processor;
use App\Classes\Modules\Transactions\Services\DeletesTransaction;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\KVPKey;
use App\Classes\ValueObjects\Constants\TransactionType;
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\Models\Booking;
use App\Models\Transaction;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

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

    /** @var Booking */
    private $booking;

    /**
     * ProcessBookingForEInvoiceV2CommandJob constructor.
     * @param Booking $booking
     */
    public function __construct(Booking $booking)
    {
        $this->booking = $booking;
    }

    public function handle()
    {
        Log::info(Carbon::now() . ': Start job - Processing single booking for E-Invoice.');
        $start   = new Carbon();

        $isAutocountDataExist = $this->booking->transactions()
        ->whereIn('transactions.type', [TransactionType::INVOICE])
        ->whereHas('attributesKVP', function ($q) {
            $q->where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE);
        })
        ->whereHas('attributesKVP', function ($q) {
            $q->where('key', KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK);
        })
        ->first();

        // $documents = $this->booking->documents()->whereIn('document_type', [DocumentType::INVOICE, DocumentType::DELIVER_ORDER, DocumentType::SUPPLIER_DELIVER_ORDER])->get();
        $documents = $this->booking->documents()->whereIn('document_type', [DocumentType::EINVOICE, DocumentType::INVOICE])->get();

        if ($documents->isEmpty() && $isAutocountDataExist) {
            Log::info("Processing for E-Invoice, booking id : " . $this->booking->marking);
            (App()->make(RegenerateInvoiceBookingV2Processor::class))->execute($this->booking);
        }
        else{
            $firstInvoiceTrx = $this->booking->transactions()
                ->whereIn('type', [TransactionType::INVOICE])
                ->withTrashed()
                ->orderBy('created_at', 'asc')
                ->first();
            if (Str::startsWith($firstInvoiceTrx->bill_no, 'EINV')) {
                Log::info("Reset and reprocess for E-Invoice, booking id : " . $this->booking->marking);
                $this->resetAndReprocess($firstInvoiceTrx);
                (App()->make(RegenerateInvoiceBookingV2Processor::class))->execute($this->booking);
            }
            else{
                Log::info("NO Processing for NORMAL Invoice, booking id : " . $this->booking->marking);
            }
        }

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

    private function resetAndReprocess($firstInvoiceTrx){
        //Get the first bill number for the first invoice transactions
        $firstInvoiceTrxBillNo = '';
        if ($firstInvoiceTrx && str_contains($firstInvoiceTrx->bill_no, '-deleted-')) {
            $firstInvoiceTrxBillNo = explode('-deleted-', $firstInvoiceTrx->bill_no)[0];
        }

        //Rename all other invoice transactions bill number
        $transactionWithSameBillNo = Transaction::where('bill_no', $firstInvoiceTrxBillNo)->withTrashed()->get();
        if ($transactionWithSameBillNo) {
            foreach ($transactionWithSameBillNo as $transaction) {
                $transaction->bill_no = $transaction->bill_no . "-deleted-" . (string)(Carbon::now()->timestamp);
                $transaction->save();
            }
        }

        //Then delete all transactions of type invoice and supplier_deliver
        $transaction = $this->booking->transactions()->whereIn('type', [TransactionType::INVOICE, TransactionType::SUPPLIER_DELIVER])->get();
        foreach ($transaction as $key => $row) {
            (App()->make(DeletesTransaction::class))->execute($row);
        }

        //Reinstate the first invoice transaction
        if ($firstInvoiceTrx && $firstInvoiceTrx->trashed()) {
            $firstInvoiceTrx->restore();
            $firstInvoiceTrx->bill_no = explode('-deleted-', $firstInvoiceTrx->bill_no)[0];
            $firstInvoiceTrx->save();
        }
        else{
            $transaction = $this->booking->transactions()->whereIn('type', [TransactionType::INVOICE]);
            Log::info('count again making sure there is an invoice: ' . $transaction->count());
            if($transaction->count() === 0){
                $firstInvoiceTrx = $this->booking->transactions()
                    ->whereIn('type', [TransactionType::INVOICE])
                    ->withTrashed()
                    ->orderBy('created_at', 'asc')
                    ->first();
                $firstInvoiceTrx->restore();
                $firstInvoiceTrx->bill_no = explode('-deleted-', $firstInvoiceTrx->bill_no)[0];
                $firstInvoiceTrx->save();
            }
        }
    }
}
