getSettings(); $this->pointsPerMinute = (int) ($settings['points_per_minute'] ?? 1); $this->maxPointsPerDay = (int) ($settings['max_points_per_day'] ?? 100); $this->requestPoints = (int) ($settings['points_for_request'] ?? 5); $this->votePoints = (int) ($settings['points_for_vote'] ?? 2); $this->giveawayWinPoints = (int) ($settings['points_for_giveaway_win'] ?? 50); $this->contestWinPoints = (int) ($settings['points_for_contest_win'] ?? 100); } public function awardPoints(User $user, int $points, string $reason): RadioListenerPoint { $pointRecord = RadioListenerPoint::awardPoints($user, $points, $reason); $this->clearUserCache($user->id); $this->clearLeaderboardCache(); return $pointRecord; } public function deductPoints(User $user, int $points, string $reason): RadioListenerPoint { $pointRecord = RadioListenerPoint::deductPoints($user, $points, $reason); $this->clearUserCache($user->id); $this->clearLeaderboardCache(); return $pointRecord; } public function getUserPoints(User $user): int { return Cache::remember(self::POINTS_CACHE_KEY . $user->id, 3600, fn (): int => (int) ($user->radio_points ?? 0)); } /** * @return array> */ public function getUserHistory(User $user, int $limit = 50): array { return RadioListenerPoint::where('user_id', $user->id) ->orderBy('earned_at', 'desc') ->limit($limit) ->get() ->toArray(); } /** * @return array */ public function getLeaderboard(int $limit = 100): array { return Cache::remember(self::LEADERBOARD_CACHE_KEY, self::LEADERBOARD_CACHE_DURATION, function () use ($limit): array { /** @var Collection $collection */ $collection = User::where('radio_points', '>', 0) ->orderBy('radio_points', 'desc') ->limit($limit) ->get(['id', 'username', 'avatar', 'radio_points']); return $collection->map(fn (User $user, int $index): array => [ 'rank' => $index + 1, 'user_id' => $user->id, 'username' => $user->username, 'avatar' => $user->avatar ?? null, 'points' => (int) $user->radio_points, ])->toArray(); }); } public function getWeeklyLeaderboard(int $limit = 50): array { return Cache::remember(self::LEADERBOARD_CACHE_KEY . '_weekly', self::LEADERBOARD_CACHE_DURATION, function () use ($limit) { $weeklyPoints = RadioListenerPoint::where('earned_at', '>=', now()->subWeek()) ->selectRaw('user_id, SUM(points) as total_points') ->groupBy('user_id') ->orderBy('total_points', 'desc') ->limit($limit) ->get(); $userIds = $weeklyPoints->pluck('user_id')->unique()->values(); $users = User::whereIn('id', $userIds) ->get(['id', 'username', 'avatar']) ->keyBy('id'); return $weeklyPoints->map(fn (object $item, int $index): array => [ 'rank' => $index + 1, 'user_id' => $item->user_id, 'username' => $users[$item->user_id]?->username ?? 'Unknown', 'avatar' => $users[$item->user_id]?->avatar ?? null, 'points' => $item->total_points, ])->toArray(); }); } public function getMonthlyLeaderboard(int $limit = 50): array { return Cache::remember(self::LEADERBOARD_CACHE_KEY . '_monthly', self::LEADERBOARD_CACHE_DURATION, function () use ($limit) { $monthlyPoints = RadioListenerPoint::where('earned_at', '>=', now()->subMonth()) ->selectRaw('user_id, SUM(points) as total_points') ->groupBy('user_id') ->orderBy('total_points', 'desc') ->limit($limit) ->get(); $userIds = $monthlyPoints->pluck('user_id')->unique()->values(); $users = User::whereIn('id', $userIds) ->get(['id', 'username', 'avatar']) ->keyBy('id'); return $monthlyPoints->map(fn (object $item, int $index): array => [ 'rank' => $index + 1, 'user_id' => $item->user_id, 'username' => $users[$item->user_id]?->username ?? 'Unknown', 'avatar' => $users[$item->user_id]?->avatar ?? null, 'points' => $item->total_points, ])->toArray(); }); } public function getUserRank(User $user): int { /** @var int $count */ $count = User::query() ->where('radio_points', '>', $user->radio_points ?? 0) ->count(); return $count + 1; } public function awardListeningPoints(User $user, int $minutes): int { $todayPoints = RadioListenerPoint::where('user_id', $user->id) ->where('earned_at', '>=', now()->startOfDay()) ->sum('points'); $availablePoints = max(0, $this->maxPointsPerDay - $todayPoints); $pointsToAward = min($minutes * $this->pointsPerMinute, $availablePoints); if ($pointsToAward > 0) { $this->awardPoints($user, $pointsToAward, 'Luisteren'); } return $pointsToAward; } public function awardRequestPoints(User $user): int { $this->awardPoints($user, $this->requestPoints, 'Song Request'); return $this->requestPoints; } public function awardVotePoints(User $user): int { $this->awardPoints($user, $this->votePoints, 'Stemmen op Request'); return $this->votePoints; } public function awardWinPoints(User $user, string $type): int { $winPoints = match ($type) { 'giveaway' => $this->giveawayWinPoints, 'contest' => $this->contestWinPoints, default => 10, }; $this->awardPoints($user, $winPoints, 'Winst: ' . $type); return $winPoints; } private function clearUserCache(int $userId): void { Cache::forget(self::POINTS_CACHE_KEY . $userId); } public function clearLeaderboardCache(): void { Cache::forget(self::LEADERBOARD_CACHE_KEY); Cache::forget(self::LEADERBOARD_CACHE_KEY . '_weekly'); Cache::forget(self::LEADERBOARD_CACHE_KEY . '_monthly'); } public function clearSettingsCache(): void { Cache::forget(self::SETTINGS_CACHE_KEY); CacheService::clearPointsSettings(); } public function getStats(): array { $totalPoints = RadioListenerPoint::sum('points'); $totalUsers = User::where('radio_points', '>', 0)->count(); return [ 'total_points_awarded' => $totalPoints, 'total_active_users' => $totalUsers, 'points_per_minute' => $this->pointsPerMinute, 'max_points_per_day' => $this->maxPointsPerDay, ]; } /** * @return array */ private function getSettings(): array { return Cache::remember(self::SETTINGS_CACHE_KEY, self::SETTINGS_CACHE_DURATION, fn (): array => WebsiteSetting::whereIn('key', [ 'points_per_minute', 'max_points_per_day', 'points_for_request', 'points_for_vote', 'points_for_giveaway_win', 'points_for_contest_win', ])->pluck('value', 'key')->toArray()); } }