<?php

namespace App\Modules\Company\Loan\Requests;

use App\Models\BorrowDenied;
use App\Models\BorrowPendingWorkers;
use App\Models\BorrowRequest;
use App\Models\LoanDenied;
use App\Models\LoanPendingWorkers;
use App\Models\LoanRequest;
use App\Models\Search;
use App\Events\Company\CreateNotificationEvent;
use App\Traits\CreateUserActionTraits;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class DeclinePendingRequest
{
    use CreateUserActionTraits;

    public function decline($payload)
    {
        $selectedpendingworkers = $payload->selectedpendingworkers;
        $workerCompanyIdForLogs = [];
        foreach ($selectedpendingworkers as $selectedpendingworker) {
            // Start transaction
            DB::beginTransaction();

            // START OF DECLINING LOAN
            $id = $selectedpendingworker['id']; // loan_pending_workers primary id
            $pendingId = $selectedpendingworker['id'];
            $loanPendingWorkerTransaction = $this->updateLoanPendingWorker($id);

            // fetch loan request details
            $loanRequest = $this->fetchLoanRequestDetails($id);

            // add declined loan pending worker to loan_declined_histories table
            $loanerCompanyId = $loanRequest[0]->loaner_company_id;
            $borrowerCompanyId = $loanRequest[0]->borrower_company_id;
            $dateRequested = $loanRequest[0]->date_requested;
            $dateFrom = $loanRequest[0]->date_from;
            $dateTo = $loanRequest[0]->date_to;
            $rate = $loanRequest[0]->rate;
            $originalRate = $loanRequest[0]->original_rate;
            $workerId = $loanRequest[0]->worker_id;
            $approverId = Auth::user()->id;
            $requesterNote = $loanRequest[0]->requester_note;
            $approverNote = $payload->approver_note;

            // preparing borrow pending worker to be saved on database
            $selectedPendingWorkerData = array(
                'loaner_company_id' => $loanerCompanyId,
                'borrower_company_id' => $borrowerCompanyId,
                'date_requested' => $dateRequested,
                'date_from' => $dateFrom,
                'date_to' => $dateTo,
                'rate' => $rate,
                'original_rate' => $originalRate,
                'worker_id' => $workerId,
                'approver_id' => $approverId,
                'requester_note' => $requesterNote,
                'approver_note' => $approverNote,
            );
            $loanDeclinedTransaction = $this->savePendingWorkerToLoanDeclinedHistories($selectedPendingWorkerData);

            // START OF DECLINING BORROW
            $id = $selectedpendingworker['id']; // borrow_pending_workers primary id
            $borrowPendingWorkerTransaction = $this->updateBorrowPendingWorker($id);

            // fetch borrow request details
            $borrowRequest = $this->fetchBorrowRequestDetails($id);

            // add cancelled borrow pending worker to borrow_denied_histories table
            $loanerCompanyId = $loanerCompanyId; // from loan_request
            $borrowerCompanyId = $borrowerCompanyId; // from loan_request
            $dateRequested = $borrowRequest[0]->date_requested;
            $requested_by = $borrowRequest[0]->requested_by;
            $dateFrom = $borrowRequest[0]->date_from;
            $dateTo = $borrowRequest[0]->date_to;
            $rate = $borrowRequest[0]->rate;
            $originalRate = $borrowRequest[0]->original_rate;
            $workerId = $borrowRequest[0]->worker_id;
            $requesterNote = $borrowRequest[0]->requester_note;
            $approverId = Auth::user()->id;
            $approverNote = $payload->approver_note;

            // preparing borrow pending worker to be saved on database
            $selectedPendingWorkerData = array(
                'loaner_company_id' => $loanerCompanyId,
                'borrower_company_id' => $borrowerCompanyId,
                'date_requested' => $dateRequested,
                'requested_by' => $requested_by,
                'date_from' => $dateFrom,
                'date_to' => $dateTo,
                'rate' => $rate,
                'original_rate' => $originalRate,
                'worker_id' => $workerId,
                'requester_note' => $requesterNote,
                'approver_id' => $approverId,
                'approver_note' => $approverNote,
            );
            $borrowDeclinedTransaction = $this->savePendingWorkerToBorroDeclinedHistories($selectedPendingWorkerData);

            // Update Search Table
            $search_id = $borrowRequest[0]->search_id;
            $updateSearchTransaction = $this->updateItemOnSearchTable($search_id);

            // Company Worker ID to be saved in logs
            array_push($workerCompanyIdForLogs, $selectedpendingworker['company_worker_id']);

            // If there's an error or queries don't do their job, rollback!
            if (!$loanPendingWorkerTransaction || !$loanDeclinedTransaction ||
                !$borrowPendingWorkerTransaction || !$borrowDeclinedTransaction ||
                !$updateSearchTransaction) {
                DB::rollBack();
            } else {
                DB::commit();
            }
        }

        // Prepare log description
        if (count($workerCompanyIdForLogs) > 1) {
            sort($workerCompanyIdForLogs);
            $lastEmployee = array_pop($workerCompanyIdForLogs);
            $workerCompanyIdForLogs = "Declined the request for Employees " . join(", ", $workerCompanyIdForLogs) . " and " . $lastEmployee;
        } else {
            $workerCompanyIdForLogs = "Declined the request for Employee" . join(", ", $workerCompanyIdForLogs);
        }
        event(new CreateNotificationEvent("update", "request", $pendingId));

        // Process the db transation in saving logs
        $this->createUserAction($workerCompanyIdForLogs);

        return response()->json(['success' => 'Data saved successfully.'])->setStatusCode(201);
    }

    public function fetchLoanRequestDetails($id)
    {
        return LoanRequest::select(
            'loan_requests.id', 'loan_requests.created_at as date_requested',
            'loan_requests.loaner_company_id', 'loan_requests.borrower_company_id',
            'loan_pending_workers.date_from', 'loan_pending_workers.date_to',
            'loan_pending_workers.rate',
            'loan_pending_workers.original_rate',
            'loan_pending_workers.worker_id',
            'loan_requests.note as requester_note')
            ->join('loan_pending_workers', 'loan_pending_workers.loan_request_id', '=', 'loan_requests.id')
            ->where('loan_pending_workers.id', $id)
            ->limit(1)->get();
    }

    public function fetchBorrowRequestDetails($id)
    {
        return BorrowRequest::select(
            'borrow_requests.id', 'borrow_requests.created_at as date_requested',
            'borrow_requests.requested_by',
            'borrow_requests.note as requester_note',
            'borrow_pending_workers.search_id',
            'borrow_pending_workers.date_from', 'borrow_pending_workers.date_to',
            'borrow_pending_workers.worker_id', 'borrow_pending_workers.rate',
            'borrow_pending_workers.original_rate')
            ->join('borrow_pending_workers', 'borrow_pending_workers.borrow_request_id', '=', 'borrow_requests.id')
            ->where('borrow_pending_workers.id', $id)
            ->limit(1)->get();
    }

    public function updateLoanPendingWorker($id)
    {
        $selectedPendingWorkerData = array(
            'status' => 'Declined',
        );
        return LoanPendingWorkers::where('id', $id)->update($selectedPendingWorkerData);
    }

    public function savePendingWorkerToLoanDeclinedHistories($selectedPendingWorkerData)
    {
        return LoanDenied::create($selectedPendingWorkerData);
    }

    public function updateBorrowPendingWorker($id)
    {
        $selectedPendingWorkerData = array(
            'status' => 'Declined',
        );
        return BorrowPendingWorkers::where('id', $id)->update($selectedPendingWorkerData);
    }

    public function savePendingWorkerToBorroDeclinedHistories($selectedPendingWorkerData)
    {
        return BorrowDenied::create($selectedPendingWorkerData);
    }

    public function updateItemOnSearchTable($search_id)
    {
        $statusData = array(
            'status' => 'Available',
        );
        return Search::where('id', $search_id)->update($statusData);
    }
}
