<?php

namespace App\Modules\HR\PermissionRequests\Services;

use App\Models\User;
use App\Modules\HR\PermissionRequests\Events\PermissionRequestApproved;
use App\Modules\HR\PermissionRequests\Events\PermissionRequestRejected;
use App\Modules\HR\PermissionRequests\Models\PermissionRequest;
use App\Modules\HR\PermissionRequests\Repositories\PermissionRequestRepository;
use App\Modules\HR\PermissionRequests\Support\PermissionRequestStatus;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\Facades\DB;

class PermissionRequestReviewService
{
    public function __construct(
        private readonly PermissionRequestRepository $requests,
        private readonly PermissionRequestAttendanceEffectService $attendanceEffects,
        private readonly Dispatcher $events,
    ) {}

    public function approve(PermissionRequest $request, User $reviewer): PermissionRequest
    {
        return $this->decide($request, $reviewer, PermissionRequestStatus::APPROVED);
    }

    public function reject(PermissionRequest $request, User $reviewer): PermissionRequest
    {
        return $this->decide($request, $reviewer, PermissionRequestStatus::REJECTED);
    }

    private function decide(PermissionRequest $request, User $reviewer, string $status): PermissionRequest
    {
        return DB::transaction(function () use ($request, $reviewer, $status): PermissionRequest {
            $locked = $this->requests->lockForTenant((int) $request->tenant_id, (int) $request->id);
            if ($locked === null) {
                abort(404);
            }
            if ($locked->status !== PermissionRequestStatus::PENDING) {
                return $locked;
            }

            $updated = $this->requests->update($locked, [
                'status' => $status,
                'reviewed_by' => $reviewer->id,
                'reviewed_at' => now(),
            ]);

            if ($status === PermissionRequestStatus::APPROVED) {
                $this->attendanceEffects->applyApproved($updated, (int) $reviewer->id);
            }

            DB::afterCommit(function () use ($updated, $reviewer, $status): void {
                if ($status === PermissionRequestStatus::APPROVED) {
                    $this->events->dispatch(new PermissionRequestApproved($updated, (int) $reviewer->id));
                } else {
                    $this->events->dispatch(new PermissionRequestRejected($updated, (int) $reviewer->id));
                }
            });

            return $updated;
        });
    }
}
