"""
Compression utilities for trace event payloads.

Provides transparent compression for large JSON payloads to reduce:
- Network bandwidth (SDK -> Redis)
- Redis memory usage
- Overall system throughput

Design principles:
- Graceful degradation: compression failures return original data
- Backward compatible: uncompressed events work as before
- Threshold-based: only compress large payloads where benefit > overhead

v0.6.1: Initial compression implementation
"""

import gzip
import base64
import json
import logging
from typing import Any, Dict, Optional

logger = logging.getLogger(__name__)

# Compression threshold in bytes (1KB)
# Payloads smaller than this are not compressed (overhead not worth it)
COMPRESSION_THRESHOLD = 1024


def maybe_compress(data: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
    """
    Compress data if it exceeds the size threshold.
    
    Uses gzip compression with base64 encoding for Redis compatibility.
    
    Args:
        data: Dictionary to potentially compress
        
    Returns:
        - Original data if below threshold or compression fails
        - Compressed format if above threshold:
          {"_compressed": True, "_data": "<base64-encoded-gzip>"}
          
    NEVER raises exceptions - returns original data on any error.
    """
    if data is None:
        return None
    
    if not isinstance(data, dict):
        return data
    
    if not data:  # Empty dict
        return data
    
    try:
        # Serialize to JSON to check size
        json_str = json.dumps(data, default=str)
        json_bytes = json_str.encode('utf-8')
        
        # Check if compression is worthwhile
        if len(json_bytes) < COMPRESSION_THRESHOLD:
            return data  # Not worth compressing
        
        # Compress with gzip
        compressed = gzip.compress(json_bytes, compresslevel=6)  # Balance speed/ratio
        
        # Base64 encode for safe transmission
        encoded = base64.b64encode(compressed).decode('utf-8')
        
        # Only use compression if it actually reduces size
        if len(encoded) >= len(json_str):
            logger.debug(f"Compression not beneficial ({len(encoded)} >= {len(json_str)}), skipping")
            return data
        
        logger.debug(f"Compressed {len(json_bytes)} bytes -> {len(encoded)} bytes ({len(encoded)/len(json_bytes)*100:.1f}%)")
        
        return {
            "_compressed": True,
            "_data": encoded
        }
        
    except Exception as e:
        # NEVER fail - return original data
        logger.debug(f"Compression failed, using uncompressed: {e}")
        return data


def maybe_decompress(data: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
    """
    Decompress data if it has the compression marker.
    
    Args:
        data: Dictionary that may be compressed
        
    Returns:
        - Decompressed original dictionary if _compressed=True
        - Original data if not compressed or decompression fails
        
    NEVER raises exceptions - returns original data on any error.
    """
    if data is None:
        return None
    
    if not isinstance(data, dict):
        return data
    
    # Check for compression marker
    if not data.get("_compressed"):
        return data  # Not compressed
    
    try:
        encoded = data.get("_data")
        if not encoded:
            logger.warning("Compressed data missing _data field")
            return data
        
        # Base64 decode
        compressed = base64.b64decode(encoded)
        
        # Gzip decompress
        json_bytes = gzip.decompress(compressed)
        
        # Parse JSON
        original = json.loads(json_bytes.decode('utf-8'))
        
        logger.debug(f"Decompressed {len(encoded)} bytes -> {len(json_bytes)} bytes")
        
        return original
        
    except Exception as e:
        # NEVER fail - return something usable
        logger.warning(f"Decompression failed: {e}")
        # Return the original dict (minus the compression markers) as fallback
        return {k: v for k, v in data.items() if k not in ("_compressed", "_data")} or data
