from django.core.cache import cache import json from datetime import datetime, timedelta from boxofficefantasy.models import Movie from django.contrib.auth.models import User from draft.constants import DraftPhase class DraftCacheKeys: def __init__(self, id): self.prefix = f"draft:{id}" @property def admins(self): return f"{self.prefix}:admins" @property def participants(self): return f"{self.prefix}:participants" @property def users(self): return f"{self.prefix}:users" @property def connected_users(self): return f"{self.prefix}:connected_users" @property def phase(self): return f"{self.prefix}:phase" @property def draft_order(self): return f"{self.prefix}:draft_order" @property def draft_index(self): return f"{self.prefix}:draft_index" # @property # def state(self): # return f"{self.prefix}:state" # @property # def current_movie(self): # return f"{self.prefix}:current_movie" # @property # def bids(self): # return f"{self.prefix}:bids" # @property # def participants(self): # return f"{self.prefix}:participants" # @property # def bid_timer_end(self): # return f"{self.prefix}:bid_timer_end" # def user_status(self, user_id): # return f"{self.prefix}:user:{user_id}:status" # def user_channel(self, user_id): # return f"{self.prefix}:user:{user_id}:channel" class DraftStateManager: def __init__(self, session_id: int): self.session_id = session_id self.cache = cache self.keys = DraftCacheKeys(session_id) self._initial_phase = self.cache.get(self.keys.phase, DraftPhase.WAITING.value) # === Phase Management === @property def phase(self) -> str: return str(self.cache.get(self.keys.phase, self._initial_phase)) @phase.setter def phase(self, new_phase: DraftPhase): self.cache.set(self.keys.phase, new_phase.value) # === Connected Users === @property def connected_participants(self) -> list[str]: return json.loads(self.cache.get(self.keys.connected_users) or "[]") def connect_participant(self, username: str): users = set(self.connected_participants) users.add(username) self.cache.set(self.keys.connected_users, json.dumps(list(users))) def disconnect_participant(self, username: str): users = set(self.connected_participants) users.discard(username) self.cache.set(self.keys.connected_users, json.dumps(list(users))) # === Draft Order === @property def draft_order(self): return json.loads(self.cache.get(self.keys.draft_order,"[]")) @draft_order.setter def draft_order(self, draft_order: list[str]): if not isinstance(draft_order, list): return self.cache.set(self.keys.draft_order,json.dumps(draft_order)) @property def draft_index(self): return self.cache.get(self.keys.draft_index,0) @draft_index.setter def draft_index(self, draft_index: int): self.cache.set(self.keys.draft_index, int(draft_index)) # === Current Nomination / Bid === def start_nomination(self, movie_id: int): self.cache.set(self.keys.current_movie, movie_id) self.cache.delete(self.keys.bids) def place_bid(self, user_id: int, amount: int): bids = self.get_bids() bids[user_id] = amount self.cache.set(self.keys.bids, json.dumps(bids)) def get_bids(self) -> dict: return json.loads(self.cache.get(self.keys.bids) or "{}") def current_movie(self) -> Movie | None: movie_id = self.cache.get(self.keys.current_movie) return Movie.objects.filter(pk=movie_id).first() if movie_id else None def start_timer(self, seconds: int): end_time = (datetime.now() + timedelta(seconds=seconds)).isoformat() self.cache.set(self.keys.timer_end, end_time) self.cache.set(self.keys.timer_end, end_time) def get_timer_end(self) -> str | None: return self.cache.get(self.keys.timer_end).decode("utf-8") if self.cache.get(self.keys.timer_end) else None # === Sync Snapshot === def get_summary(self) -> dict: return { "phase": self.phase, "draft_order": self.draft_order, "draft_index": self.draft_index, "connected_participants": self.connected_participants, # "current_movie": self.cache.get(self.keys.current_movie), # "bids": self.get_bids(), # "timer_end": self.get_timer_end(), }