from datetime import timedelta from django.http import HttpRequest from django.utils import timezone from ninja import Router from ninja.decorators import decorate_view from games.decorators import require_game_enabled from .models import PRESS_BONUS_SECONDS, ClockTimer, Press from .schemas import ClockStateOut, PlayerStatsOut from .scoring import ranked_players router = Router() PREFIX = "/events/{event_path}/clock" @router.get(f"{PREFIX}/current", response=ClockStateOut) @decorate_view(require_game_enabled(path="clock")) def current_state(request: HttpRequest, event_path: str): timer = ClockTimer.current(request.event) timer.reset_if_expired() now = timezone.now() next_press_at = None cooldown_seconds = None if request.user.is_authenticated: last_press = ( Press.objects.filter(player=request.user, event=request.event) .order_by("-pressed_at") .first() ) if last_press is not None: candidate = last_press.pressed_at + timedelta( seconds=last_press.cooldown_seconds ) if candidate > now: next_press_at = candidate cooldown_seconds = last_press.cooldown_seconds return { "server_time": now, "end_time": timer.end_time, "initial_duration": timer.initial_duration, "press_bonus_seconds": PRESS_BONUS_SECONDS, "next_press_at": next_press_at, "cooldown_seconds": cooldown_seconds, } @router.get(f"{PREFIX}/me", response=PlayerStatsOut) @decorate_view(require_game_enabled(path="clock")) def my_stats(request: HttpRequest, event_path: str): ranked = list( ranked_players(request.event) .values("id", "clock_points", "rank") .order_by("-clock_points", "id") ) total_players = len(ranked) my_index = next( (i for i, row in enumerate(ranked) if row["id"] == request.user.id), None ) mine = ranked[my_index] if my_index is not None else None above = ranked[my_index - 1] if my_index is not None and my_index > 0 else None below = ( ranked[my_index + 1] if my_index is not None and my_index + 1 < total_players else None ) return { "points": mine["clock_points"] if mine else 0.0, "rank": mine["rank"] if mine else total_players, "total_players": total_players, "points_above": above["clock_points"] if above else None, "points_below": below["clock_points"] if below else None, }