# Fix 1: Unicode Logging Fix
# Add this near the top of the file, after the logging setup

# Configure logging
os.makedirs("logs", exist_ok=True)
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')

# Fix for Windows unicode console output
if sys.platform == 'win32':
    import codecs
    sys.stdout = codecs.getwriter('utf-8')(sys.stdout.buffer, 'strict')
    sys.stderr = codecs.getwriter('utf-8')(sys.stderr.buffer, 'strict')

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s | %(levelname)s | %(message)s",
    handlers=[
        logging.FileHandler(f"logs/solana_mev_{timestamp}.log", encoding='utf-8'),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)

# Fix 2: Improved RPC Manager with simplified endpoints
class RPCManager:
    """Manages RPC endpoints with failover and rate-limiting"""
    
    def __init__(self):
        # Load RPC endpoints
        self.primary_rpc = CONFIG["RPC_URL"]
        self.primary_ws = CONFIG["WS_URL"]
        
        # Backup RPC endpoints - simplified list
        self.rpc_endpoints = deque([
            self.primary_rpc,
            "https://api.mainnet-beta.solana.com",
            "https://solana-api.projectserum.com"
        ])
        
        # Backup WebSocket endpoints
        self.ws_endpoints = deque([
            self.primary_ws,
            "wss://api.mainnet-beta.solana.com",
            "wss://solana-api.projectserum.com"
        ])
        
        # Rate limiting
        self.rate_limit_counts = {endpoint: 0 for endpoint in self.rpc_endpoints}
        self.last_request_time = 0.0
        self.request_times = deque(maxlen=CONFIG["MAX_REQUESTS_PER_SECOND"])
        self.in_cooldown = False
        self.cooldown_until = 0.0
        
        # Current endpoints
        self.current_rpc = self.primary_rpc
        self.current_ws = self.primary_ws
        
        # API key for Helius
        self.api_key = CONFIG["API_KEY"]
        
        logger.info(f"RPC Manager initialized with primary endpoint: {self.primary_rpc}")

# Fix 3: Modified process_account_batch method with better error handling
async def process_account_batch(self, account_batch):
    """Process a batch of account addresses by fetching their data"""
    try:
        rpc_url = self.rpc_manager.get_current_rpc()
        
        # Get account data for the batch
        async with aiohttp.ClientSession() as session:
            getMultipleAccounts_requests = []
            
            # Create batches of 100 accounts (RPC limit)
            for i in range(0, len(account_batch), 100):
                sub_batch = account_batch[i:i+100]
                
                getMultipleAccounts_requests.append(
                    session.post(
                        rpc_url,
                        json={
                            "jsonrpc": "2.0",
                            "id": i,
                            "method": "getMultipleAccounts",
                            "params": [
                                sub_batch,
                                {"encoding": "base64"}
                            ]
                        },
                        headers=self.rpc_manager.get_headers()
                    )
                )
            
            # Execute all requests
            responses = await asyncio.gather(*getMultipleAccounts_requests, return_exceptions=True)
            
            # Process responses
            for response in responses:
                if isinstance(response, Exception):
                    logger.error(f"Error in batch request: {response}")
                    continue
                    
                data = await response.json()
                
                # Check for rate limiting
                if "error" in data and "429" in str(data.get("error")):
                    self.rpc_manager.handle_rate_limit(rpc_url)
                    continue
                
                if "result" in data and "value" in data["result"]:
                    accounts = data["result"]["value"]
                    
                    # Process each account
                    for i, account in enumerate(accounts):
                        try:
                            # Calculate index with bounds checking
                            idx = i % 100 + int(data["id"])*100
                            if idx >= len(account_batch):
                                logger.error(f"Index calculation error: {idx} >= {len(account_batch)}")
                                continue
                                
                            pubkey = account_batch[idx]
                            
                            # Skip if already seen
                            if pubkey in self.pools_seen:
                                continue
                                
                            # Mark as seen
                            self.pools_seen.add(pubkey)
                            self.stats.accounts_scanned += 1
                            
                            # Skip if no data
                            if not account or not account.get("data"):
                                continue
                            
                            # Decode base64 data
                            try:
                                data_array = account.get("data", ["", "base64"])
                                if isinstance(data_array, list) and len(data_array) >= 1:
                                    raw_data = base64.b64decode(data_array[0])
                                else:
                                    continue
                            except Exception as e:
                                logger.error(f"Error decoding account data: {e}")
                                continue
                            
                            # Add to pending analysis
                            self.pending_analysis.append((pubkey, raw_data))
                        except IndexError as e:
                            logger.error(f"List index out of range during account processing: {e}")
                            continue
                        except Exception as e:
                            logger.error(f"Error processing account: {e}")
            
            # Analyze the pending batch
            if self.pending_analysis:
                await self.analyze_pending_batch()
                
    except Exception as e:
        logger.error(f"Error processing account batch: {str(e)}")
        logger.error(traceback.format_exc())

# Fix 4: Improved analyze_batch_gpu with better error handling for safely accessing token_mint
async def analyze_batch_gpu(self):
    """Analyze pool batch using GPU acceleration"""
    batch_size = len(self.pending_analysis)
    
    # Prepare batch data for GPU
    max_data_len = max(len(data) for _, data in self.pending_analysis)
    max_data_len = min(max_data_len, 2048)  # Cap at reasonable size
    
    # Create batch tensor
    batch_data = torch.zeros((batch_size, max_data_len), dtype=torch.uint8, device=self.device)
    batch_lengths = torch.zeros(batch_size, dtype=torch.long, device=self.device)
    pubkeys = []
    
    for i, (pubkey, data) in enumerate(self.pending_analysis):
        pubkeys.append(pubkey)
        data_len = min(len(data), max_data_len)
        batch_data[i, :data_len] = torch.tensor(list(data[:data_len]), dtype=torch.uint8, device=self.device)
        batch_lengths[i] = data_len
    
    # Run GPU-accelerated analysis
    try:
        # Fix for older PyTorch versions: Use torch.cuda.amp.autocast() instead of torch.amp.autocast()
        with torch.cuda.amp.autocast(enabled=CONFIG["USE_AMP"]):
            # ... [existing analysis code] ...
            
            # Process secure pools with improved error handling
            for i in secure_indices:
                i = i.item()
                pubkey = pool_pubkeys[i]
                pool_idx = potential_pool_indices[i].item()
                data_size = batch_lengths[potential_pool_indices[i]].item()
                
                # Get raw data for this pool
                raw_data = self.pending_analysis[pool_idx][1]
                
                # Get security details
                mint_offset_idx = mint_offset_indices[i].item()
                mint_offset = self.SECURITY_CHECK_OPTIONS[mint_offset_idx][0]
                
                lp_range_idx = lp_range_indices[i].item()
                lp_range = (self.LP_LOCK_CHECK_OPTIONS[lp_range_idx][0], self.LP_LOCK_CHECK_OPTIONS[lp_range_idx][1])
                lp_percentage = best_percentages[i].item()
                
                # Extract token mint
                token_mint = await self.get_token_mint_from_pool(pubkey)
                
                # Skip if no token mint found
                if not token_mint:
                    logger.error(f"Could not extract token mint from pool {pubkey}, skipping")
                    continue
                
                # Extract exit liquidity
                exit_liquidity = await self.get_exit_liquidity(raw_data)
                
                # Safe log display of token mint with fallbacks
                safe_token_display = token_mint[:8] if token_mint and len(token_mint) >= 8 else 'Unknown'
                
                # Create pool info
                pool_info = {
                    "pubkey": pubkey,
                    "token_mint": token_mint,
                    "size": data_size,
                    "first_byte": raw_data[0] if len(raw_data) > 0 else None,
                    "mint_revoked": True,
                    "mint_offset": mint_offset,
                    "lp_locked": True,
                    "lp_percentage": lp_percentage,
                    "lp_range": lp_range,
                    "exit_liquidity_sol": exit_liquidity,
                    "is_secure": True,
                    "discovery_time": datetime.now().strftime("%H:%M:%S")
                }
                
                # Create token security record for trading system
                security = TokenSecurity(
                    mint_authority_revoked=True,
                    lp_locked=True,
                    has_exit_liquidity=exit_liquidity >= CONFIG["MIN_EXIT_LIQUIDITY_SOL"],
                    exit_liquidity_sol=exit_liquidity,
                    pool_address=pubkey,
                    token_mint=token_mint,
                    valid=exit_liquidity >= CONFIG["MIN_EXIT_LIQUIDITY_SOL"],
                    exists=True,
                    discovery_time=datetime.now().strftime("%H:%M:%S"),
                    first_byte=raw_data[0] if len(raw_data) > 0 else None,
                    size=data_size,
                    mint_offset=mint_offset,
                    lp_range=lp_range,
                    lp_percentage=lp_percentage
                )
                
                # Add to secure pools list if not already present
                if not any(p.get("pubkey") == pubkey for p in self.secure_pools):
                    self.secure_pools.append(pool_info)
                    
                    # Use a safe log message without problematic emoji
                    logger.info(f"Found new secure pool: {pubkey}, Token: {safe_token_display}, "
                              f"LP Lock: {lp_percentage:.1f}%, Liquidity: {exit_liquidity:.2f} SOL")
                    
                # Update security cache for both scanner and trader
                if token_mint:
                    self.security_cache[token_mint] = (time.time(), security)
                    
                    # Add to trader's validator cache if possible
                    if hasattr(self.trader, 'token_validator') and hasattr(self.trader.token_validator, 'security_cache'):
                        self.trader.token_validator.security_cache[token_mint] = (time.time(), security)
                        
                        # Also update trader's valid tokens set
                        if hasattr(self.trader, 'valid_tokens') and security.valid:
                            self.trader.valid_tokens.add(token_mint)
                            logger.info(f"Added token {safe_token_display} to trader's valid tokens cache")
    except Exception as e:
        logger.error(f"Error in GPU batch analysis: {e}")
        logger.error(traceback.format_exc())
        # Fall back to CPU analysis
        await self.analyze_batch_cpu()                                fix this 2nd portion with the correct code from the begining portion of this message please write all of the code do not use place holders for anything it needs every line properly written and ready to run after copying and pasting it to my program