""" Scouting Helper Functions Handles creation of scout opportunities after pack openings and embed formatting for the scouting feature. """ import asyncio import datetime import logging import random import discord from api_calls import db_get, db_post from helpers.utils import int_timestamp, midnight_timestamp from helpers.discord_utils import get_team_embed from helpers.constants import IMAGES, PD_SEASON logger = logging.getLogger("discord_app") SCOUT_TOKENS_PER_DAY = 2 SCOUT_WINDOW_SECONDS = 1800 # 30 minutes # Rarity value → display symbol RARITY_SYMBOLS = { 8: "\U0001f7e1", # HoF — yellow 5: "\U0001f7e3", # MVP — purple 3: "\U0001f535", # All-Star — blue 2: "\U0001f7e2", # Starter — green 1: "\u26aa", # Reserve — white 0: "\u26ab", # Replacement — black } async def get_scout_tokens_used(team_id: int) -> int: """Return how many scout tokens a team has used today.""" used_today = await db_get( "rewards", params=[ ("name", "Scout Token"), ("team_id", team_id), ("created_after", midnight_timestamp()), ], ) return used_today["count"] if used_today else 0 def _build_card_lines(cards: list[dict]) -> list[tuple[int, str]]: """Build a shuffled list of (player_id, display_line) tuples.""" lines = [] for card in cards: player = card["player"] rarity_val = player["rarity"]["value"] symbol = RARITY_SYMBOLS.get(rarity_val, "\u26ab") lines.append( ( player["player_id"], f"{symbol} {player['rarity']['name']} — {player['p_name']}", ) ) random.shuffle(lines) return lines def build_scout_embed( opener_team: dict, cards: list[dict], card_lines: list[tuple[int, str]] = None, expires_unix: int = None, ) -> tuple[discord.Embed, list[tuple[int, str]]]: """Build the embed shown above the scout buttons. Shows a shuffled list of cards (rarity + player name) so scouters know what's in the pack but not which button maps to which card. Returns (embed, card_lines) so the view can store the shuffled order. """ embed = get_team_embed(title="Scout Opportunity!", team=opener_team) if card_lines is None: card_lines = _build_card_lines(cards) card_list = "\n".join(line for _, line in card_lines) if expires_unix: time_line = f"Scout window closes ." else: time_line = "Scout window closes in **30 minutes**." embed.description = ( f"**{opener_team['lname']}** just opened a pack!\n\n" f"**Cards in this pack:**\n{card_list}\n\n" f"Pick a card — but which is which?\n" f"Costs 1 Scout Token (2 per day, resets at midnight Central).\n" f"{time_line}" ) embed.set_footer( text=f"Paper Dynasty Season {PD_SEASON} \u2022 One player per pack", icon_url=IMAGES["logo"], ) return embed, card_lines def build_scouted_card_list( card_lines: list[tuple[int, str]], scouted_cards: dict[int, list[str]], ) -> str: """Rebuild the card list marking scouted cards with scouter team names. Parameters ---------- card_lines : shuffled list of (player_id, display_line) tuples scouted_cards : {player_id: [team_name, ...]} for each claimed card """ result = [] for player_id, line in card_lines: teams = scouted_cards.get(player_id) if teams: count = len(teams) names = ", ".join(f"*{t}*" for t in teams) if count == 1: result.append(f"{line} \u2014 \u2714\ufe0f {names}") else: result.append(f"{line} \u2014 \u2714\ufe0f x{count} ({names})") else: result.append(line) return "\n".join(result) async def create_scout_opportunity( pack_cards: list[dict], opener_team: dict, channel: discord.TextChannel, opener_user, context, ) -> None: """Create a scout opportunity and post the ScoutView to the channel. Called after display_cards() completes in open_st_pr_packs(). Wrapped in try/except so scouting failures never crash pack opening. Parameters ---------- pack_cards : list of card dicts from a single pack opener_team : team dict for the pack opener channel : the #pack-openings channel opener_user : discord.Member or discord.User who opened the pack context : the command context (Context or Interaction), used to get bot """ from discord_ui.scout_view import ScoutView # Only create scout opportunities in the pack-openings channel if not channel or channel.name != "pack-openings": return if not pack_cards: return now = datetime.datetime.now() expires_at = int_timestamp(now + datetime.timedelta(seconds=SCOUT_WINDOW_SECONDS)) created = int_timestamp(now) card_ids = [c["id"] for c in pack_cards] try: scout_opp = await db_post( "scout_opportunities", payload={ "pack_id": pack_cards[0].get("pack_id"), "opener_team_id": opener_team["id"], "card_ids": card_ids, "expires_at": expires_at, "created": created, }, ) except Exception as e: logger.error(f"Failed to create scout opportunity: {e}") return expires_unix = int( (now + datetime.timedelta(seconds=SCOUT_WINDOW_SECONDS)).timestamp() ) embed, card_lines = build_scout_embed( opener_team, pack_cards, expires_unix=expires_unix ) # Get bot reference from context bot = getattr(context, "bot", None) or getattr(context, "client", None) view = ScoutView( scout_opp_id=scout_opp["id"], cards=pack_cards, opener_team=opener_team, opener_user_id=opener_user.id, bot=bot, expires_unix=expires_unix, ) view.card_lines = card_lines try: msg = await channel.send(embed=embed, view=view) view.message = msg except Exception as e: logger.error(f"Failed to post scout opportunity message: {e}")