import random import copy from datetime import datetime from app.players import get_all_players, ROLE_ORDER DEFAULT_SETTINGS = { "purse_per_team": 1200, # lakhs "min_squad_size": 18, "max_squad_size": 25, "max_overseas": 8, "timer_seconds": 30, "timer_reset_on_bid": True, "bid_increment": 5, "unsold_recall": True, "auto_pass_enabled": True, } SET_ORDER = ["SET_A","SET_B","SET_C","SET_D","SET_E","SET_F","SET_G","SET_H","SET_I","SET_J"] def create_room(room_code: str, host_id: str, host_name: str, settings: dict = None) -> dict: s = copy.deepcopy(DEFAULT_SETTINGS) if settings: s.update(settings) return { "room_code": room_code, "host_id": host_id, "created_at": datetime.utcnow().isoformat(), "state": "lobby", "settings": s, "teams": { host_id: { "id": host_id, "name": host_name, "team_name": f"{host_name}'s XI", "purse": s["purse_per_team"], "players": [], "is_host": True, "connected": True, } }, "players": get_all_players(), "auction_queue": [], "current_player_id": None, "current_bid": 0, "current_bidder_id": None, "bid_history": [], "sold_log": [], "unsold_players": [], "chat_messages": [], "status_message": "Waiting for host to start.", } def add_team(room: dict, user_id: str, username: str, team_name: str = None) -> dict: if user_id not in room["teams"]: room["teams"][user_id] = { "id": user_id, "name": username, "team_name": team_name or f"{username}'s XI", "purse": room["settings"]["purse_per_team"], "players": [], "is_host": False, "connected": True, } else: room["teams"][user_id]["connected"] = True return room def get_player(room: dict, pid: str): return next((p for p in room["players"] if p["id"] == pid), None) def build_queue(room: dict, order: str = "set") -> list: players = [p for p in room["players"] if p["status"] == "available"] if order == "set": players.sort(key=lambda p: ( SET_ORDER.index(p.get("auction_set", "SET_J")) )) elif order == "role": players.sort(key=lambda p: ( ROLE_ORDER.index(p["role"]) if p["role"] in ROLE_ORDER else 99 )) elif order == "marquee_first": players.sort(key=lambda p: ( ["MARQUEE","A+","A"].index(p.get("category","A")) if p.get("category") in ["MARQUEE","A+","A"] else 99 )) elif order == "india_first": players.sort(key=lambda p: (0 if not p["overseas"] else 1)) elif order == "random": random.shuffle(players) return [p["id"] for p in players] def start_next(room: dict) -> dict: if not room["auction_queue"]: room["state"] = "ended" room["status_message"] = "Auction complete!" return room pid = room["auction_queue"].pop(0) player = get_player(room, pid) if not player: return start_next(room) room["current_player_id"] = pid room["current_bid"] = player["base_price"] room["current_bidder_id"] = None room["state"] = "auction" room["status_message"] = f"Bidding open for {player['name']}!" return room def place_bid(room: dict, bidder_id: str, amount: int): """Returns (ok, message, room).""" if room["state"] != "auction": return False, "Auction not active", room team = room["teams"].get(bidder_id) player = get_player(room, room["current_player_id"]) if not team or not player: return False, "Invalid state", room settings = room["settings"] inc = settings["bid_increment"] min_bid = room["current_bid"] + inc if room["current_bidder_id"] else room["current_bid"] if amount < min_bid: return False, f"Min bid is ₹{min_bid}L", room if team["purse"] < amount: return False, "Insufficient purse", room if len(team["players"]) >= settings["max_squad_size"]: return False, "Squad full", room if player["overseas"]: overseas_count = sum( 1 for pid in team["players"] if get_player(room, pid) and get_player(room, pid)["overseas"] ) if overseas_count >= settings["max_overseas"]: return False, "Overseas limit reached", room if bidder_id == room["current_bidder_id"]: return False, "You are already the highest bidder", room room["current_bid"] = amount room["current_bidder_id"] = bidder_id room["bid_history"].append({ "player_id": room["current_player_id"], "bidder_id": bidder_id, "bidder_name": team["name"], "amount": amount, "ts": datetime.utcnow().isoformat(), }) return True, f"₹{amount}L by {team['name']}", room def sell_current(room: dict): pid = room["current_player_id"] bidder = room["current_bidder_id"] if not pid or not bidder: return mark_unsold(room) player = get_player(room, pid) team = room["teams"][bidder] amount = room["current_bid"] player["status"] = "sold" player["bought_by"] = bidder team["purse"] -= amount team["players"].append(pid) room["sold_log"].append({ "player_id": pid, "player_name": player["name"], "team_id": bidder, "team_name": team["team_name"], "price": amount, "ts": datetime.utcnow().isoformat(), }) room["current_player_id"] = None room["current_bidder_id"] = None room["current_bid"] = 0 room["status_message"] = f"🔨 SOLD! {player['name']} → {team['team_name']} ₹{amount}L" return room def mark_unsold(room: dict): pid = room["current_player_id"] if pid: p = get_player(room, pid) if p: p["status"] = "unsold" room["unsold_players"].append(pid) room["status_message"] = f"❌ UNSOLD — {p['name']}" room["current_player_id"] = None room["current_bidder_id"] = None room["current_bid"] = 0 return room def recall_unsold(room: dict) -> dict: for pid in room["unsold_players"]: p = get_player(room, pid) if p: p["status"] = "available" room["auction_queue"].append(pid) room["unsold_players"] = [] room["status_message"] = "Unsold players re-added!" return room def final_summary(room: dict) -> dict: summaries = [] for tid, team in room["teams"].items(): bought = [] for pid in team["players"]: p = get_player(room, pid) sale = next((s for s in room["sold_log"] if s["player_id"] == pid), None) if p: bought.append({**p, "price_paid": sale["price"] if sale else 0}) spent = room["settings"]["purse_per_team"] - team["purse"] summaries.append({ "team": team, "players": bought, "spent": spent, "purse_remaining": team["purse"], "overseas_count": sum(1 for p in bought if p.get("overseas")), "role_counts": {r: sum(1 for p in bought if p["role"] == r) for r in ROLE_ORDER}, }) return { "teams": summaries, "total_sold": len(room["sold_log"]), "total_unsold": len(room["unsold_players"]), "most_expensive": max(room["sold_log"], key=lambda s: s["price"], default=None), "unsold_players": [get_player(room, pid)["name"] for pid in room["unsold_players"] if get_player(room, pid)], }