#!/usr/bin/env python3 """ Profile Manager - Business Logic Handles profile data management without UI dependencies """ import os import json from typing import Dict, List, Optional, Any from dataclasses import dataclass, asdict from datetime import datetime # Import the user profile integration system from user_profile_integration import UserProfileIntegration @dataclass class UserProfile: """User profile data structure""" name: str created_date: str last_played: str games_played: int = 0 total_score: int = 0 best_score: int = 0 settings: Dict[str, Any] = None achievements: List[str] = None def __post_init__(self): if self.settings is None: self.settings = { "difficulty": "normal", "sound_volume": 50, "music_volume": 50, "screen_shake": True, "auto_save": True } if self.achievements is None: self.achievements = [] class ProfileDataManager: """Core business logic for profile management""" def __init__(self, profiles_file: str = "user_profiles.json"): self.profiles_file = profiles_file self.profiles: Dict[str, UserProfile] = {} self.active_profile: Optional[str] = None # Initialize user profile integration system self.integration = UserProfileIntegration(profiles_file) self.device_id = self.integration.get_device_id() self.api_enabled = self.integration.api_enabled self.load_profiles() def load_profiles(self) -> bool: """Load profiles from JSON file""" if not os.path.exists(self.profiles_file): return True try: with open(self.profiles_file, 'r') as f: data = json.load(f) self.profiles = { name: UserProfile(**profile_data) for name, profile_data in data.get('profiles', {}).items() } self.active_profile = data.get('active_profile') return True except (json.JSONDecodeError, KeyError) as e: print(f"Error loading profiles: {e}") self.profiles = {} return False def save_profiles(self) -> bool: """Save profiles to JSON file""" data = { 'profiles': { name: asdict(profile) for name, profile in self.profiles.items() }, 'active_profile': self.active_profile } try: with open(self.profiles_file, 'w') as f: json.dump(data, f, indent=2) return True except IOError as e: print(f"Error saving profiles: {e}") return False def create_profile(self, name: str) -> tuple[bool, str]: """Create a new profile. Returns (success, message)""" name = name.strip() if not name: return False, "Profile name cannot be empty" if name in self.profiles: return False, f"Profile '{name}' already exists" now = datetime.now().isoformat() profile = UserProfile( name=name, created_date=now, last_played=now ) self.profiles[name] = profile if not self.save_profiles(): del self.profiles[name] return False, "Failed to save profile" # Register with API server if available if self.api_enabled: result = self.integration.register_new_user(name) if result: print(f"Profile {name} registered with server") else: print(f"Warning: Profile {name} created locally but not registered with server") return True, f"Profile '{name}' created successfully" def delete_profile(self, name: str) -> tuple[bool, str]: """Delete a profile. Returns (success, message)""" if name not in self.profiles: return False, f"Profile '{name}' not found" del self.profiles[name] if self.active_profile == name: self.active_profile = None if not self.save_profiles(): return False, "Failed to save changes" return True, f"Profile '{name}' deleted" def set_active_profile(self, name: str) -> tuple[bool, str]: """Set the active profile. Returns (success, message)""" if name not in self.profiles: return False, f"Profile '{name}' not found" self.active_profile = name self.profiles[name].last_played = datetime.now().isoformat() if not self.save_profiles(): return False, "Failed to save changes" # Update integration system to load the new profile self.integration.reload_profile() return True, f"Active profile set to '{name}'" def get_profile_list(self) -> List[str]: """Get list of profile names""" return list(self.profiles.keys()) def get_profile(self, name: str) -> Optional[UserProfile]: """Get a specific profile""" return self.profiles.get(name) def get_active_profile(self) -> Optional[UserProfile]: """Get the currently active profile""" if self.active_profile: return self.profiles.get(self.active_profile) return None def update_profile_settings(self, name: str, setting: str, value: Any) -> tuple[bool, str]: """Update a profile setting. Returns (success, message)""" if name not in self.profiles: return False, f"Profile '{name}' not found" profile = self.profiles[name] if setting not in profile.settings: return False, f"Setting '{setting}' not found" # Validate setting values if not self._validate_setting(setting, value): return False, f"Invalid value for setting '{setting}'" profile.settings[setting] = value if not self.save_profiles(): return False, "Failed to save changes" return True, f"Setting '{setting}' updated" def _validate_setting(self, setting: str, value: Any) -> bool: """Validate setting values""" validations = { 'difficulty': lambda v: v in ['easy', 'normal', 'hard', 'expert'], 'sound_volume': lambda v: isinstance(v, int) and 0 <= v <= 100, 'music_volume': lambda v: isinstance(v, int) and 0 <= v <= 100, 'screen_shake': lambda v: isinstance(v, bool), 'auto_save': lambda v: isinstance(v, bool) } validator = validations.get(setting) return validator(value) if validator else True def get_leaderboard_data(self, leaderboard_type: str = "device") -> List[Dict[str, Any]]: """Get leaderboard data""" if not self.api_enabled: return [] try: if leaderboard_type == "device": return self.integration.get_device_leaderboard(10) else: # global return self.integration.get_global_leaderboard(10) except Exception as e: print(f"Error loading leaderboard: {e}") return [] def get_profile_stats(self, name: str) -> Optional[Dict[str, Any]]: """Get detailed profile statistics""" if name not in self.profiles: return None profile = self.profiles[name] integration_info = self.integration.get_profile_info() if self.api_enabled else {} try: created = datetime.fromisoformat(profile.created_date).strftime("%Y-%m-%d") last_played = datetime.fromisoformat(profile.last_played).strftime("%Y-%m-%d") except: created = "Unknown" last_played = "Unknown" return { 'profile': profile, 'created_formatted': created, 'last_played_formatted': last_played, 'integration_info': integration_info, 'api_enabled': self.api_enabled } class SettingsManager: """Helper class for managing profile settings""" DIFFICULTY_OPTIONS = ["easy", "normal", "hard", "expert"] VOLUME_RANGE = (0, 100, 5) # min, max, step @classmethod def adjust_difficulty(cls, current: str, direction: int) -> str: """Adjust difficulty setting""" try: current_index = cls.DIFFICULTY_OPTIONS.index(current) new_index = (current_index + direction) % len(cls.DIFFICULTY_OPTIONS) return cls.DIFFICULTY_OPTIONS[new_index] except ValueError: return "normal" @classmethod def adjust_volume(cls, current: int, direction: int) -> int: """Adjust volume setting""" min_val, max_val, step = cls.VOLUME_RANGE new_value = current + (direction * step) return max(min_val, min(max_val, new_value)) @classmethod def toggle_boolean(cls, current: bool) -> bool: """Toggle boolean setting""" return not current @classmethod def get_setting_display_value(cls, setting: str, value: Any) -> str: """Get display string for setting value""" if setting == 'difficulty': return value.title() elif setting in ['sound_volume', 'music_volume']: return f"{value}%" elif setting in ['screen_shake', 'auto_save']: return "On" if value else "Off" else: return str(value)