<?php

namespace App\Services\Admin\HR;

use App\Concerns\HasRoleChecks;
use App\Enums\Role;
use App\Models\Employee;
use App\Models\User;
use App\Services\S3PresignedService;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

class EmployeeService
{
    use HasRoleChecks;

    public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator
    {
        $paginator = User::query()
            ->select(['id', 'email', 'username', 'is_active'])
            ->where(fn ($q) => $q->whereHas('employee')->orWhereHas('roles', fn ($rq) => $rq->where('name', 'Owner')))
            ->with([
                'userProfile' => fn ($q) => $q->select(['id', 'user_id', 'full_name', 'phone_number', 'gender']),
                'employee' => fn ($q) => $q->select(['id', 'user_id', 'join_date', 'employment_status', 'base_salary']),
                'roles' => fn ($q) => $q->select(['id', 'name']),
                'media',
            ])
            ->when(! self::hasAnyRole([Role::DEVELOPER, Role::OWNER, Role::DIREKTUR, Role::ADMIN_TOKO]), function ($q) {
                $userRoles = auth()->user()->roles->pluck('name');
                $q->whereHas('roles', fn ($rq) => $rq->whereIn('name', $userRoles));
            })
            ->when(self::hasAnyRole([Role::ADMIN_TOKO, Role::DIREKTUR]), fn ($q) => $q->whereDoesntHave('roles', fn ($rq) => $rq->where('name', Role::ADMIN_BAHAN_BAKU->value)))
            ->when($search, fn ($q) => $q->whereHas('userProfile', fn ($uq) => $uq->where('full_name', 'like', "%{$search}%")))
            ->when($filters['employment_status'] ?? null, fn ($q, $status) => $q->whereHas('employee', fn ($eq) => $eq->where('employment_status', $status)))
            ->when(isset($filters['is_active']) && $filters['is_active'] !== '', fn ($q) => $q->where('is_active', filter_var($filters['is_active'], FILTER_VALIDATE_BOOLEAN)))
            ->when($filters['gender'] ?? null, fn ($q, $gender) => $q->whereHas('userProfile', fn ($uq) => $uq->where('gender', $gender)))
            ->orderBy($sort, $direction)
            ->paginate($perPage);

        $paginator->getCollection()->transform(function (User $user) {
            $media = $user->getFirstMedia('photos');
            $user->photo_url = $media
                ? app(S3PresignedService::class)->getTemporaryUrl($media->getPath())
                : null;

            return $user;
        });

        return $paginator;
    }

    public function getAll(): Collection
    {
        return Employee::with(['user.userProfile', 'user.roles'])
            ->whereHas('user', fn ($q) => $q->where('is_active', true))
            ->get()
            ->map(fn (Employee $employee) => [
                'id' => $employee->id,
                'name' => $employee->user?->userProfile?->full_name ?? '-',
            ]);
    }

    public function store(array $data): User
    {
        return DB::transaction(function () use ($data) {
            $user = User::create([
                'email' => $data['email'],
                'username' => $data['username'],
                'password' => config('auth.password_default'),
                'is_active' => true,
            ]);

            $user->assignRole($data['role']);

            $user->userProfile()->create([
                'full_name' => $data['full_name'],
                'phone_number' => $data['phone_number'] ?? null,
                'gender' => $data['gender'] ?? null,
                'birth_date' => $data['birth_date'] ?? null,
                'address' => $data['address'] ?? null,
            ]);

            if ($data['role'] !== 'owner') {
                $user->employee()->create([
                    'join_date' => $data['join_date'],
                    'resign_date' => $data['resign_date'] ?? null,
                    'employment_status' => $data['employment_status'],
                    'base_salary' => $data['base_salary'],
                ]);
            }

            return $user;
        });
    }

    public function update(User $user, array $data): User
    {
        DB::transaction(function () use ($user, $data) {
            $user->update([
                'email' => $data['email'],
                'username' => $data['username'],
            ]);

            $user->syncRoles($data['role']);

            $user->userProfile()->updateOrCreate([], [
                'full_name' => $data['full_name'],
                'phone_number' => $data['phone_number'] ?? null,
                'gender' => $data['gender'] ?? null,
                'birth_date' => $data['birth_date'] ?? null,
                'address' => $data['address'] ?? null,
            ]);

            if ($data['role'] !== 'owner') {
                $user->employee()->updateOrCreate([], [
                    'join_date' => $data['join_date'],
                    'resign_date' => $data['resign_date'] ?? null,
                    'employment_status' => $data['employment_status'],
                    'base_salary' => $data['base_salary'],
                ]);
            } else {
                $user->employee()->delete();
            }
        });

        return $user->fresh(['userProfile', 'employee']);
    }

    public function destroy(User $user): bool
    {
        return DB::transaction(function () use ($user) {
            $user->employee()->delete();
            $user->userProfile()->delete();

            return $user->delete();
        });
    }

    public function toggleActive(User $user): User
    {
        $user->update(['is_active' => ! $user->is_active]);

        return $user;
    }

    public function resetPassword(User $user): User
    {
        $defaultPassword = config('auth.password_default');
        $user->update(['password' => $defaultPassword]);

        return $user;
    }
}
