"""Code bundle packaging utilities.

Creates tarballs of the user's tau-bench directory for remote execution.
"""

import io
import tarfile
from pathlib import Path

from rich.console import Console

console = Console()

# Files/directories to exclude from the bundle
EXCLUDE_PATTERNS = [
    "__pycache__",
    "*.pyc",
    "*.pyo",
    ".git",
    ".venv",
    "venv",
    ".env",
    "*.egg-info",
    ".pytest_cache",
    ".mypy_cache",
    ".ruff_cache",
    "node_modules",
    ".DS_Store",
]


def should_exclude(path: Path, base_path: Path) -> bool:
    """Check if a path should be excluded from the bundle.
    
    Args:
        path: Path to check
        base_path: Base path of the tau-bench directory
        
    Returns:
        True if the path should be excluded
    """
    name = path.name
    
    for pattern in EXCLUDE_PATTERNS:
        if pattern.startswith("*"):
            # Suffix match
            if name.endswith(pattern[1:]):
                return True
        else:
            # Exact match
            if name == pattern:
                return True
    
    return False


def create_bundle(tau_bench_path: Path) -> bytes:
    """Create a tarball of the tau-bench directory.
    
    Args:
        tau_bench_path: Path to the tau-bench directory
        
    Returns:
        The tarball bytes
        
    Raises:
        ValueError: If the path is not a valid tau-bench directory
    """
    if not tau_bench_path.exists():
        raise ValueError(f"Path does not exist: {tau_bench_path}")
    
    if not (tau_bench_path / "tau_bench").exists():
        raise ValueError(f"Not a valid tau-bench directory: {tau_bench_path}")
    
    buffer = io.BytesIO()
    
    with tarfile.open(fileobj=buffer, mode="w:gz") as tar:
        file_count = 0
        
        for item in tau_bench_path.rglob("*"):
            if item.is_file():
                # Check exclusions
                if any(should_exclude(p, tau_bench_path) for p in item.relative_to(tau_bench_path).parents):
                    continue
                if should_exclude(item, tau_bench_path):
                    continue
                
                # Add to archive with relative path
                arcname = str(item.relative_to(tau_bench_path.parent))
                tar.add(item, arcname=arcname)
                file_count += 1
        
        console.print(f"  Packaged {file_count} files")
    
    buffer.seek(0)
    return buffer.read()


def get_bundle_size_mb(data: bytes) -> float:
    """Get the size of a bundle in MB.
    
    Args:
        data: The bundle bytes
        
    Returns:
        Size in MB
    """
    return len(data) / (1024 * 1024)

