<?php

namespace App\Modules\HR\Leave\Repositories;

use App\Modules\HR\Leave\Models\LeaveRequest;
use App\Modules\HR\Leave\Support\LeaveRequestStatus;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\LazyCollection;

class LeaveRequestRepository
{
    public function create(array $data): LeaveRequest
    {
        return LeaveRequest::query()->create($data);
    }

    public function findForTenant(int $tenantId, int $id): ?LeaveRequest
    {
        return LeaveRequest::query()
            ->where('tenant_id', $tenantId)
            ->whereKey($id)
            ->first();
    }

    public function lockForTenant(int $tenantId, int $id): ?LeaveRequest
    {
        return LeaveRequest::query()
            ->where('tenant_id', $tenantId)
            ->whereKey($id)
            ->lockForUpdate()
            ->first();
    }

    public function paginateForTenant(int $tenantId, int $perPage = 20): LengthAwarePaginator
    {
        return LeaveRequest::query()
            ->where('tenant_id', $tenantId)
            ->with(['employee', 'leaveType'])
            ->orderByDesc('created_at')
            ->paginate($perPage);
    }

    /**
     * @return LazyCollection<int, LeaveRequest>
     */
    public function cursorForTenant(int $tenantId): LazyCollection
    {
        return LeaveRequest::query()
            ->where('tenant_id', $tenantId)
            ->with(['employee:id,tenant_id,full_name', 'leaveType:id,tenant_id,name'])
            ->orderByDesc('id')
            ->cursor();
    }

    /**
     * HR-approved leave overlapping a date range (for payroll day clipping).
     *
     * @return Collection<int, LeaveRequest>
     */
    public function approvedOverlappingRange(
        int $tenantId,
        int $employeeId,
        string $rangeStart,
        string $rangeEnd,
        ?bool $isPaid = null,
    ): Collection {
        $q = LeaveRequest::query()
            ->where('tenant_id', $tenantId)
            ->where('employee_id', $employeeId)
            ->where('status', LeaveRequestStatus::HR_APPROVED)
            ->whereDate('start_date', '<=', $rangeEnd)
            ->whereDate('end_date', '>=', $rangeStart)
            ->with(['employee', 'leaveType:id,tenant_id,is_paid']);
        if ($isPaid !== null) {
            $q->whereHas('leaveType', fn ($t) => $t->where('is_paid', $isPaid));
        }

        return $q->get();
    }

    public function paginateForEmployee(int $tenantId, int $employeeId, int $perPage = 20): LengthAwarePaginator
    {
        return LeaveRequest::query()
            ->where('tenant_id', $tenantId)
            ->where('employee_id', $employeeId)
            ->with(['leaveType'])
            ->orderByDesc('created_at')
            ->paginate($perPage);
    }

    /**
     * @return Collection<int, LeaveRequest>
     */
    public function pendingForTenant(int $tenantId): Collection
    {
        return LeaveRequest::query()
            ->where('tenant_id', $tenantId)
            ->whereIn('status', [LeaveRequestStatus::PENDING, LeaveRequestStatus::MANAGER_APPROVED])
            ->with(['employee', 'leaveType'])
            ->orderBy('created_at')
            ->get();
    }

    /**
     * @param  array<string, mixed>  $data
     */
    public function update(LeaveRequest $request, array $data): LeaveRequest
    {
        $request->update($data);

        return $request->fresh(['employee', 'leaveType']);
    }
}
