<?php

namespace App\Services\Admin\HR;

use App\Concerns\HasRoleChecks;
use App\Enums\LeaveRequestStatus;
use App\Enums\Role;
use App\Models\LeaveRequest;
use App\Services\NotificationService;
use Carbon\Carbon;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;

class LeaveRequestService
{
    use HasRoleChecks;

    public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator
    {
        return LeaveRequest::query()
            ->select(['id', 'employee_id', 'start_date', 'end_date', 'total_days', 'status', 'created_at'])
            ->with(['employee.user.userProfile'])
            ->when(! self::hasAnyRole([Role::DEVELOPER, Role::OWNER, Role::DIREKTUR, Role::ADMIN_TOKO]), fn ($q) => $q->whereHas('employee', fn ($eq) => $eq->where('user_id', auth()->id())))
            ->when($search, fn ($q) => $q->whereHas('employee.user.userProfile', fn ($uq) => $uq->where('full_name', 'like', "%{$search}%")))
            ->when($filters['status'] ?? null, function ($query, $status) {
                $query->where('status', $status);
            })
            ->orderBy($sort, $direction)
            ->paginate($perPage);
    }

    public function store(array $data): LeaveRequest
    {
        $leaveRequest = DB::transaction(function () use ($data) {
            $employee = auth()->user()->employee;

            if (! $employee) {
                throw ValidationException::withMessages([
                    'employee' => 'Anda tidak terdaftar sebagai karyawan.',
                ]);
            }

            $startDate = new Carbon($data['start_date']);
            $endDate = new Carbon($data['end_date']);
            $totalDays = $startDate->diffInDays($endDate) + 1;

            return LeaveRequest::create([
                'employee_id' => $employee->id,
                'start_date' => $data['start_date'],
                'end_date' => $data['end_date'],
                'total_days' => $totalDays,
                'status' => LeaveRequestStatus::PENDING,
            ]);
        });

        $leaveRequest->load('employee.user');

        NotificationService::notify(
            roles: [Role::OWNER, Role::DEVELOPER, Role::DIREKTUR, Role::ADMIN_TOKO],
            title: 'Pengajuan Cuti Baru',
            body: "Pengajuan cuti {$leaveRequest->total_days} hari oleh ".auth()->user()->full_name.'.',
            url: route('admin.hr.leave-requests.index'),
            additionalUser: $leaveRequest->employee->user ?? null,
        );

        return $leaveRequest;
    }

    public function update(LeaveRequest $leaveRequest, array $data): LeaveRequest
    {
        if (! $this->canModify($leaveRequest)) {
            throw ValidationException::withMessages([
                'employee' => 'Anda tidak memiliki akses untuk mengubah cuti ini.',
            ]);
        }

        return DB::transaction(function () use ($leaveRequest, $data) {
            $startDate = new Carbon($data['start_date']);
            $endDate = new Carbon($data['end_date']);
            $totalDays = $startDate->diffInDays($endDate) + 1;

            $leaveRequest->update([
                'start_date' => $data['start_date'],
                'end_date' => $data['end_date'],
                'total_days' => $totalDays,
            ]);

            return $leaveRequest;
        });
    }

    public function destroy(LeaveRequest $leaveRequest): bool
    {
        if (! $this->canModify($leaveRequest)) {
            throw ValidationException::withMessages([
                'employee' => 'Anda tidak memiliki akses untuk menghapus cuti ini.',
            ]);
        }

        return $leaveRequest->delete();
    }

    public function approve(LeaveRequest $leaveRequest): LeaveRequest
    {
        $leaveRequest->update([
            'status' => LeaveRequestStatus::APPROVED,
            'verified_by_id' => auth()->id(),
            'verified_at' => now(),
        ]);

        $employeeUser = $leaveRequest->employee->user ?? null;

        NotificationService::notify(
            roles: [Role::OWNER, Role::DEVELOPER, Role::DIREKTUR, Role::ADMIN_TOKO],
            title: 'Cuti Disetujui',
            body: "Cuti {$leaveRequest->employee->name} telah disetujui oleh ".auth()->user()->full_name.'.',
            url: route('admin.hr.leave-requests.index'),
            additionalUser: $employeeUser,
        );

        return $leaveRequest;
    }

    public function reject(LeaveRequest $leaveRequest): LeaveRequest
    {
        $leaveRequest->update([
            'status' => LeaveRequestStatus::REJECTED,
            'verified_by_id' => auth()->id(),
            'verified_at' => now(),
        ]);

        $employeeUser = $leaveRequest->employee->user ?? null;

        NotificationService::notify(
            roles: [Role::OWNER, Role::DEVELOPER, Role::DIREKTUR, Role::ADMIN_TOKO],
            title: 'Cuti Ditolak',
            body: "Cuti {$leaveRequest->employee->name} telah ditolak oleh ".auth()->user()->full_name.'.',
            url: route('admin.hr.leave-requests.index'),
            additionalUser: $employeeUser,
        );

        return $leaveRequest;
    }

    private function canModify(LeaveRequest $leaveRequest): bool
    {
        if (self::hasAnyRole([Role::DEVELOPER, Role::OWNER])) {
            return true;
        }

        return $leaveRequest->employee->user_id === auth()->id();
    }
}
