""" Scouting Helper Functions Handles creation of scout opportunities after pack openings and embed formatting for the scouting feature. """ 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 scout per player", 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}")