query('q', '')); $q = ltrim($raw, '@'); if (strlen($q) < 2) { return response()->json(['data' => []]); } $perPage = min((int) $request->query('per_page', 4), 8); $users = User::query() ->where('is_active', 1) ->whereNull('deleted_at') ->where(function ($qb) use ($q) { $qb->whereRaw('LOWER(username) LIKE ?', ['%' . strtolower($q) . '%']) ->orWhereRaw('LOWER(name) LIKE ?', ['%' . strtolower($q) . '%']); }) ->with(['profile', 'statistics']) ->orderByRaw('LOWER(username) = ? DESC', [strtolower($q)]) // exact match first ->orderBy('username') ->limit($perPage) ->get(['id', 'username', 'name']); $data = $users->map(function (User $user) { $username = strtolower((string) ($user->username ?? '')); $avatarHash = $user->profile?->avatar_hash; $uploadsCount = (int) ($user->statistics?->uploads_count ?? 0); return [ 'id' => $user->id, 'type' => 'user', 'username' => $username, 'name' => $user->name ?? $username, 'avatar_url' => AvatarUrl::forUser((int) $user->id, $avatarHash, 64), 'uploads_count' => $uploadsCount, 'profile_url' => '/@' . $username, ]; }); return response()->json(['data' => $data]); } }