import json import random from django.contrib.auth.decorators import login_required from django.http import HttpRequest, JsonResponse from django.views.decorators.http import require_GET, require_POST from fupogfakta.models import GameSession, Player SESSION_CODE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" SESSION_CODE_LENGTH = 6 MAX_CODE_GENERATION_ATTEMPTS = 20 JOINABLE_STATUSES = { GameSession.Status.LOBBY, GameSession.Status.LIE, GameSession.Status.GUESS, GameSession.Status.REVEAL, } def _json_body(request: HttpRequest) -> dict: if not request.body: return {} try: return json.loads(request.body) except json.JSONDecodeError: return {} def _generate_session_code() -> str: return "".join(random.choices(SESSION_CODE_ALPHABET, k=SESSION_CODE_LENGTH)) def _create_unique_session_code() -> str: for _ in range(MAX_CODE_GENERATION_ATTEMPTS): code = _generate_session_code() if not GameSession.objects.filter(code=code).exists(): return code raise RuntimeError("Could not generate unique session code") @require_POST @login_required def create_session(request: HttpRequest) -> JsonResponse: code = _create_unique_session_code() session = GameSession.objects.create(host=request.user, code=code) return JsonResponse( { "session": { "code": session.code, "status": session.status, "host_id": session.host_id, "current_round": session.current_round, } }, status=201, ) @require_POST def join_session(request: HttpRequest) -> JsonResponse: payload = _json_body(request) code = str(payload.get("code", "")).strip().upper() nickname = str(payload.get("nickname", "")).strip() if not code: return JsonResponse({"error": "Session code is required"}, status=400) if len(nickname) < 2 or len(nickname) > 40: return JsonResponse({"error": "Nickname must be between 2 and 40 characters"}, status=400) try: session = GameSession.objects.get(code=code) except GameSession.DoesNotExist: return JsonResponse({"error": "Session not found"}, status=404) if session.status not in JOINABLE_STATUSES: return JsonResponse({"error": "Session is not joinable"}, status=400) if Player.objects.filter(session=session, nickname__iexact=nickname).exists(): return JsonResponse({"error": "Nickname already taken"}, status=409) player = Player.objects.create(session=session, nickname=nickname) return JsonResponse( { "player": { "id": player.id, "nickname": player.nickname, "score": player.score, }, "session": { "code": session.code, "status": session.status, }, }, status=201, ) @require_GET def session_detail(request: HttpRequest, code: str) -> JsonResponse: session_code = code.strip().upper() try: session = GameSession.objects.get(code=session_code) except GameSession.DoesNotExist: return JsonResponse({"error": "Session not found"}, status=404) players = list( session.players.order_by("nickname").values( "id", "nickname", "score", "is_connected", ) ) return JsonResponse( { "session": { "code": session.code, "status": session.status, "host_id": session.host_id, "current_round": session.current_round, "players_count": len(players), }, "players": players, } )