import os
import sys
import traceback
import json
import threading
from datetime import datetime

class SolanaLogger:
    """
    Comprehensive logging utility with debug toggling and advanced error tracking.
    """
    _instance = None
    _lock = threading.Lock()

    def __new__(cls, name=None):
        """Singleton pattern to ensure a single logging instance."""
        if not cls._instance:
            with cls._lock:
                if not cls._instance:
                    cls._instance = super().__new__(cls)
        return cls._instance

    def __init__(self, name=None):
        """Initialize logging configuration."""
        if not hasattr(self, '_initialized'):
            # Base configuration
            self.base_log_dir = r'C:\solana_rust_bot\logs'
            self.debug_enabled = False
            self.module_name = name if name else 'unknown'
            
            # Load logging configuration
            self.config_path = os.path.join(self.base_log_dir, 'logging_config.json')
            self._load_config()
            self._ensure_log_directories()
            
            self._initialized = True

    def _ensure_log_directories(self):
        """Create log directories if they don't exist."""
        log_dirs = [
            os.path.join(self.base_log_dir, subdir) 
            for subdir in ['debug', 'errors', 'info', 'system', 'trading', 'archived']
        ]
        for dir_path in log_dirs:
            os.makedirs(dir_path, exist_ok=True)

    def _load_config(self):
        """Load logging configuration from a JSON file."""
        try:
            if os.path.exists(self.config_path):
                with open(self.config_path, 'r') as config_file:
                    config = json.load(config_file)
                    self.debug_enabled = config.get('debug_mode', False)
                    self.max_log_size = config.get('max_log_size', 204800)  # 200 KB
                    self.clean_threshold = config.get('clean_threshold', 102400)  # 100 KB
            else:
                self._save_config()
        except Exception as e:
            print(f"Error loading logging config: {e}")
            self.debug_enabled = False

    def _save_config(self):
        """Save logging configuration to a JSON file."""
        try:
            with open(self.config_path, 'w') as config_file:
                json.dump({'debug_mode': self.debug_enabled,
                            'max_log_size': self.max_log_size,
                            'clean_threshold': self.clean_threshold}, config_file)
        except Exception as e:
            print(f"Error saving logging config: {e}")

    def _check_log_size(self, log_type='system'):
        """Check log file size and refresh it if it exceeds the threshold."""
        log_file_path = os.path.join(self.base_log_dir, log_type, f"{log_type}.log")
        if os.path.exists(log_file_path):
            current_size = os.path.getsize(log_file_path)
            if current_size >= self.clean_threshold:
                # Clear the log file to begin anew
                with open(log_file_path, 'w'):
                    pass  # Just open and close to clear the file

    def _write_log(self, message, log_type='system', caller_name=None, is_debug=False, extra=None):
        """Write log message with comprehensive error tracking."""
        if is_debug and not self.debug_enabled:
            return
        
        if caller_name is None:
            caller_name = self.module_name
            
        if log_type not in ['debug', 'errors', 'info', 'system', 'trading', 'critical']:
            log_type = 'system'
        
        timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
        
        # Format the log entry with optional extra parameters
        extra_str = self._format_extra(extra)
        log_entry = f"{timestamp} | {log_type.upper()} | {caller_name}: {message}{extra_str}\n"
        
        # Use 'errors' directory for critical logs
        if log_type == 'critical':
            log_type = 'errors'
        
        # Check log size before writing
        self._check_log_size(log_type)
        
        log_file_path = os.path.join(self.base_log_dir, log_type, f"{log_type}.log")
        
        try:
            with open(log_file_path, 'a') as log_file:
                log_file.write(log_entry)
        except Exception as e:
            print(f"Logging error: {e}", file=sys.stderr)

    def _format_extra(self, extra):
        """Format extra parameters for logging."""
        if not extra:
            return ""
        try:
            return f" | {json.dumps(extra)}"
        except:
            return f" | {str(extra)}"

    def debug(self, message, caller_name=None, extra=None):
        """Log debug messages with contextual information."""
        self._write_log(message, 'debug', caller_name, is_debug=True, extra=extra)

    def info(self, message, log_type='info', caller_name=None, extra=None):
        """Log informational messages with contextual information."""
        self._write_log(message, log_type, caller_name, extra=extra)

    def error(self, message, log_type='errors', caller_name=None, include_traceback=True, extra=None):
        """Log error messages with detailed context and traceback."""
        full_message = message
        if include_traceback:
            trace = traceback.format_exc()
            full_message += f"\n--- TRACEBACK ---\n{trace}"
        self._write_log(full_message, log_type, caller_name, extra=extra)

    def critical(self, message, caller_name=None, extra=None):
        """Log critical error messages with a traceback."""
        full_message = message
        trace = traceback.format_exc()
        full_message += f"\n--- TRACEBACK ---\n{trace}"
        self._write_log(full_message, 'critical', caller_name, extra=extra)

    def exception(self, message, caller_name=None, extra=None):
        """Log exception messages with a traceback."""
        full_message = message
        trace = traceback.format_exc()
        full_message += f"\n--- TRACEBACK ---\n{trace}"
        self._write_log(full_message, 'errors', caller_name, extra=extra)

# Convenience functions for logging
def log_debug(message, caller_name=None, extra=None):
    logger = SolanaLogger()
    logger.debug(message, caller_name, extra)

def log_info(message, log_type='info', caller_name=None, extra=None):
    logger = SolanaLogger()
    logger.info(message, log_type, caller_name, extra)

def log_error(message, log_type='errors', caller_name=None, include_traceback=True, extra=None):
    logger = SolanaLogger()
    logger.error(message, log_type, caller_name, include_traceback, extra)

def log_critical(message, caller_name=None, extra=None):
    logger = SolanaLogger()
    logger.critical(message, caller_name, extra)

def log_exception(message, caller_name=None, extra=None):
    logger = SolanaLogger()
    logger.exception(message, caller_name, extra)

def toggle_debug(enable=None):
    logger = SolanaLogger()
    return logger.toggle_debug(enable)  DO YOU SEE THIS ?