<?php

namespace App\Jobs;

use Exception;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Queue\SerializesModels;
use App\Enums\LeaveCreditAdjustmentType;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Suiterus\Adg\Models\LeaveManagement\LeaveType;
use Suiterus\Adg\Services\Attendance\AttendanceService;
use Suiterus\Adg\Controllers\LeaveManagement\Table\Credits;
use Suiterus\Adg\Models\LeaveManagement\LeaveCreditHistory;
use Suiterus\Adg\Models\LeaveManagement\Crediting\LeaveBalance;

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

    protected $userId;
    protected $leaveTypeId;
    protected $isReset;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($userId, $leaveTypeId, $isReset)
    {
        $this->userId = $userId;
        $this->leaveTypeId = $leaveTypeId;
        $this->isReset = $isReset;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        DB::connection(env('ADG_DB_CONNECTION'))->beginTransaction();
        try {
            $leaveType = LeaveType::find($this->leaveTypeId);
            $user = User::find($this->userId);
            $isUpdateLeaveBalance = true;

            $lastMonth = Carbon::now()->subMonth();
            $dateHired = Carbon::parse($user->employeeMetaInfo->date_hired);
            $isNewlyHired = $lastMonth->format('Y-m') == $dateHired->format('Y-m');

            if (strtolower($leaveType->title) == 'vacation leave' || strtolower($leaveType->title) == 'sick leave') {
                $currentDay = $isNewlyHired ? $dateHired : Carbon::now()->subMonth()->startOfMonth();
                $lastDay = Carbon::now()->subMonth()->endOfMonth();
                $attendanceService = new AttendanceService($user);
                $dtr = $attendanceService->getTimekeepingAttendanceDisplay($currentDay, $lastDay);
                $absences = [];
                $absences = $attendanceService->getAbsentValues($dtr);

                if (!empty($absences)) {
                    $isUpdateLeaveBalance = false;
                }
            }

            $leaveBalance = LeaveBalance::where([
                ['user_id', $this->userId],
                ['leave_type_id', $this->leaveTypeId]
            ])->first();

            if ($this->isReset && strtolower($leaveType->title) != 'vacation leave' && strtolower($leaveType->title) != 'sick leave') {

                $leaveBalance->balance = $leaveType->initial_points;
                $leaveBalance->save();

                LeaveCreditHistory::create([
                    'user_id' => $this->userId,
                    'leave_type_id' => $this->leaveTypeId,
                    'credits' => $leaveType->initial_points ?? $leaveType->initial_points,
                    'resulting_balance' => $leaveType->initial_points ?? $leaveType->initial_points,
                    'leave_adjustment_type' => LeaveCreditAdjustmentType::RESET,
                    'remarks' => 'Balance adjusted: Yearly reset',
                    'period' => Carbon::now()->format('Y-m-d'),
                    'created_by' => 0,
                ]);

            } else if (($isUpdateLeaveBalance && $leaveBalance)) {
                $frequency = '';

                if ($leaveType->increase_type == 1) {
                    $frequency = 'Monthly ';
                } else if ($leaveType->increase_type == 2) {
                    $frequency = 'Yearly ';
                }

                if ($isNewlyHired && $leaveType->increase_type == 1) {
                    $remainingDays = 30 - $dateHired->format('d'); // 30 is fixed representing calendar days. 
                    $remainingDays = $remainingDays < 0 ? 0 : $remainingDays;
                    $creditObj = new Credits;
                    $newHiredCredits = $creditObj->getCreditsEarnedDaily()[$remainingDays];
                }

                $credits = $newHiredCredits ?? $leaveType->default_increase;

                $remarks = $frequency . $leaveType->title . ' Earned';
                $increased_balance = $leaveBalance->balance + $credits;

                LeaveCreditHistory::create([
                    'user_id' => $this->userId,
                    'leave_type_id' => $this->leaveTypeId,
                    'credits' => $credits,
                    'resulting_balance' => $increased_balance,
                    'leave_adjustment_type' => LeaveCreditAdjustmentType::EARNED,
                    'remarks' => $remarks,
                    'period' => Carbon::now()->format('Y-m-d'),
                    'created_by' => 0,
                ]);

                $leaveBalance->balance = $increased_balance;
                $leaveBalance->save();
            }

            DB::connection(env('ADG_DB_CONNECTION'))->commit();
        } catch (Exception $e) {
            DB::connection(env('ADG_DB_CONNECTION'))->rollBack();
            $this->fail($e);
        }
    }
}
