"""Group and player management utilities.""" from typing import Dict, List, Optional from datetime import datetime, timedelta from app.extensions import db from app.models import Player, Group, PlayerFeedback from app.utils.logger import log_action def get_player_status_info(player_id: int) -> Dict: """Get comprehensive status information for a player. Args: player_id: Player ID to query Returns: Dictionary with status information """ player = Player.query.get(player_id) if not player: return { 'online': False, 'status': 'unknown', 'last_seen': None, 'latest_feedback': None } # Check if player is online (seen in last 5 minutes) is_online = False if player.last_seen: delta = datetime.utcnow() - player.last_seen is_online = delta.total_seconds() < 300 # Get latest feedback latest_feedback = PlayerFeedback.query.filter_by(player_id=player_id)\ .order_by(PlayerFeedback.timestamp.desc())\ .first() return { 'online': is_online, 'status': player.status, 'last_seen': player.last_seen.isoformat() if player.last_seen else None, 'last_seen_ago': _format_time_ago(player.last_seen) if player.last_seen else 'Never', 'latest_feedback': { 'status': latest_feedback.status, 'message': latest_feedback.message, 'error': latest_feedback.error, 'timestamp': latest_feedback.timestamp.isoformat() } if latest_feedback else None } def get_group_statistics(group_id: int) -> Dict: """Get statistics for a group. Args: group_id: Group ID to query Returns: Dictionary with group statistics """ group = Group.query.get(group_id) if not group: return { 'total_players': 0, 'online_players': 0, 'total_content': 0, 'error_count': 0 } total_players = group.player_count total_content = group.content_count # Count online players online_players = 0 error_count = 0 five_min_ago = datetime.utcnow() - timedelta(minutes=5) for player in group.players: if player.last_seen and player.last_seen >= five_min_ago: online_players += 1 if player.status == 'error': error_count += 1 return { 'group_id': group_id, 'group_name': group.name, 'total_players': total_players, 'online_players': online_players, 'offline_players': total_players - online_players, 'total_content': total_content, 'error_count': error_count } def assign_player_to_group(player_id: int, group_id: Optional[int]) -> bool: """Assign a player to a group or unassign if group_id is None. Args: player_id: Player ID to assign group_id: Group ID to assign to, or None to unassign Returns: True if successful, False otherwise """ try: player = Player.query.get(player_id) if not player: log_action('error', f'Player {player_id} not found') return False old_group_id = player.group_id player.group_id = group_id db.session.commit() if group_id: group = Group.query.get(group_id) log_action('info', f'Player "{player.name}" assigned to group "{group.name}"') else: log_action('info', f'Player "{player.name}" unassigned from group') return True except Exception as e: db.session.rollback() log_action('error', f'Error assigning player to group: {str(e)}') return False def bulk_assign_players_to_group(player_ids: List[int], group_id: Optional[int]) -> int: """Assign multiple players to a group. Args: player_ids: List of player IDs to assign group_id: Group ID to assign to, or None to unassign Returns: Number of players successfully assigned """ count = 0 try: for player_id in player_ids: player = Player.query.get(player_id) if player: player.group_id = group_id count += 1 db.session.commit() if group_id: group = Group.query.get(group_id) log_action('info', f'Bulk assigned {count} players to group "{group.name}"') else: log_action('info', f'Bulk unassigned {count} players from groups') return count except Exception as e: db.session.rollback() log_action('error', f'Error bulk assigning players: {str(e)}') return 0 def get_online_players_count() -> int: """Get count of online players (seen in last 5 minutes). Returns: Number of online players """ five_min_ago = datetime.utcnow() - timedelta(minutes=5) return Player.query.filter(Player.last_seen >= five_min_ago).count() def get_players_by_status(status: str) -> List[Player]: """Get all players with a specific status. Args: status: Status to filter by Returns: List of Player instances """ return Player.query.filter_by(status=status).all() def _format_time_ago(dt: datetime) -> str: """Format datetime as 'time ago' string. Args: dt: Datetime to format Returns: Formatted string like '5 minutes ago' """ delta = datetime.utcnow() - dt seconds = delta.total_seconds() if seconds < 60: return f'{int(seconds)} seconds ago' elif seconds < 3600: return f'{int(seconds / 60)} minutes ago' elif seconds < 86400: return f'{int(seconds / 3600)} hours ago' else: return f'{int(seconds / 86400)} days ago'